Skip to content

fix(security): eliminate false positives in NonceVerification for empty/isset#1355

Open
faisalahammad wants to merge 7 commits into
WordPress:trunkfrom
faisalahammad:fix/1350-nonce-verification-false-positives
Open

fix(security): eliminate false positives in NonceVerification for empty/isset#1355
faisalahammad wants to merge 7 commits into
WordPress:trunkfrom
faisalahammad:fix/1350-nonce-verification-false-positives

Conversation

@faisalahammad

@faisalahammad faisalahammad commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

The WPCS NonceVerificationSniff incorrectly flags empty() and isset() checks on superglobals as "Processing form data without nonce verification". These functions only check existence, they don't process form data values.

Created a custom PluginCheck.Security.NonceVerification sniff that extends the WPCS sniff and overrides needs_nonce_check() to return false for empty()/isset() contexts.

Fixes #1350

Changes

phpcs-sniffs/PluginCheck/Sniffs/Security/NonceVerificationSniff.php (new)

Custom sniff extending WPCS NonceVerificationSniff. Overrides needs_nonce_check() to treat empty()/isset() as safe.

protected function needs_nonce_check( $stackPtr, array $cache_keys ) {
    if ( ContextHelper::is_in_isset_or_empty( $this->phpcsFile, $stackPtr ) ) {
        // empty() and isset() only check existence, they do not process the value.
        return false;
    }
    return parent::needs_nonce_check( $stackPtr, $cache_keys );
}

phpcs-rulesets/plugin-check.ruleset.xml

Switched from WordPress.Security.NonceVerification to PluginCheck.Security.NonceVerification.

Before:

<rule ref="WordPress.Security.NonceVerification">

After:

<rule ref="PluginCheck.Security.NonceVerification">

phpcs-sniffs/PluginCheck/ruleset.xml

Registered the new custom sniff.

After:

<rule ref="PluginCheck.Security.NonceVerification" />

Testing

Test 1: False positive - empty() on superglobal

function verify() {
    if (empty($_REQUEST['g-recaptcha-response'])) {
        return false;
    }
}

Result: No warning (fixed)

Test 2: False positive - wrapper function with empty() check

function verifyNonce($key, $action = -1) {
    if(empty($_POST[$key])){
        return false;
    }
    return wp_verify_nonce(sanitize_text_field(wp_unslash($_POST[$key])), $action);
}

Result: No false positive on empty() check

Test 3: True positive - direct superglobal processing

function bad() {
    $data = $_POST['data'];
}

Result: Error "Processing form data without nonce verification" (still caught)

All 14 PHPCS sniff tests pass, composer lint passes, composer phpstan passes, CodeRabbit review clean.

Open WordPress Playground Preview

…ty/isset

- Add custom PluginCheck.Security.NonceVerificationSniff extending WPCS sniff
- Override needs_nonce_check() to return false for empty()/isset() contexts
- These only check existence, not process form data
- Update rulesets to use custom sniff instead of WPCS one
- Add unit tests for false positive cases (empty/isset) and true positives

Fixes WordPress#1350
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: faisalahammad <faisalahammad@git.wordpress.org>
Co-authored-by: Tsjippy <tsjippy@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some more false positive examples

1 participant