Skip to content

fix: suppress phpcs false-positives in database-check (closes #122) - #200

Merged
ivdimova merged 1 commit into
devfrom
fix/v0-11-database-check-security
May 12, 2026
Merged

ivdimova merged 1 commit into
devfrom
fix/v0-11-database-check-security

Conversation

@pluginslab

Copy link
Copy Markdown
Owner

Summary

Closes the SQL injection issue in `database-check.php` — but as a documentation/suppression PR rather than a behavior change. Net: +13 / -3 lines, 1 file touched.

Context

When #122 was filed, the file had real exposure: `$where_clauses` was concatenated unescaped into a query. The file has since been refactored — all dynamic SQL now goes through `$wpdb->prepare()` with `%s` placeholders, and the values passed are either literal pattern strings or `$wpdb->esc_like()`'d constants. No user input ever touches the query string directly.

What remained were 3 phpcs false-positives.

Suppressions added (with rationale comments)

Rule Line Why it's a false positive
`WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare` 306 (existing `prepare()` block) The WHERE clause is built from literal `"option_value LIKE %s"` fragments in a fixed-size loop over `$suspicious_patterns`. The `%s` count always matches `...$values`, but phpcs can't trace through `implode` + variadic spread to verify that.
`WordPress.DB.SlowDBQuery.slow_db_query_meta_key` 515 (SELECT) Security audit that intentionally scans usermeta for injected payloads. `LIMIT 50` + admin-only `permission_callback` keep the blast radius small. Caching skipped on purpose — stale results would hide a fresh injection.
`WordPress.DB.SlowDBQuery.slow_db_query_meta_key` 531 (PHP array key) phpcs flags the literal string `'meta_key'` used as a PHP array key, as if it were a WP_Query argument.

What I did NOT change

The SQL itself. All three queries in this file already use `$wpdb->prepare()` with safe placeholder patterns. The phpcs warnings were noise, not findings.

Verification

  • `composer lint` — clean (was 0 errors / 2 warnings, now 0 / 0)
  • `npm test` — 96 passing, unchanged
  • All queries still go through `$wpdb->prepare()` with proper `%s` placeholders

What's still queued for v0.11

After this lands, the remaining WP.org blockers are:

Test plan

  • Build check passes
  • PHP lint passes (specifically: 0 warnings for database-check.php)
  • JS lint passes
  • Unit tests pass
  • Manual: run the database-check security ability from chat → completes without errors and surfaces any findings

🤖 Generated with Claude Code

…122)

When this issue was filed, database-check.php had real SQL-injection
exposure (unescaped \$where_clauses concatenated into the query). The
file has since been refactored — all dynamic SQL now goes through
\$wpdb->prepare() with %s placeholders, and the variables passed to
prepare() are either literal pattern strings or \$wpdb->esc_like()'d
constants. No user input ever touches the query string directly.

What remained were three phpcs false-positives:

1. WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare (line 306)
   The WHERE clause is built from literal "option_value LIKE %s"
   fragments in a fixed-size loop. phpcs can't trace through implode +
   variadic spread to verify that the %s count matches ...\$values.

2. WordPress.DB.SlowDBQuery.slow_db_query_meta_key (line 515 SELECT)
   This is a security audit that intentionally scans usermeta for
   injected payloads. Slowness is the trade-off; LIMIT 50 + admin-only
   permission_callback keep blast radius small. Caching skipped on
   purpose — stale results would hide a fresh injection.

3. WordPress.DB.SlowDBQuery.slow_db_query_meta_key (line 531 array key)
   phpcs flags the PHP array key 'meta_key' as if it were a WP_Query
   argument. Same rule, false positive on a literal string key.

Each suppression has a rationale comment explaining why. No behavior
change — the SQL was already safe.

Tests: 96 passing, unchanged.
PHP lint: clean (0 errors, 0 warnings, was 0 errors / 2 warnings).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

@ivdimova ivdimova left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pure false-positive suppression with clear rationale comments. No logic changes. Safe to merge.

@ivdimova
ivdimova merged commit c8de658 into dev May 12, 2026
4 checks passed
@ivdimova
ivdimova deleted the fix/v0-11-database-check-security branch May 12, 2026 21:18
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.

2 participants