Skip to content

Compare user identities strictly - #767

Closed
obenland wants to merge 1 commit into
WordPress:trunkfrom
obenland:strict-identity-comparisons
Closed

Compare user identities strictly#767
obenland wants to merge 1 commit into
WordPress:trunkfrom
obenland:strict-identity-comparisons

Conversation

@obenland

@obenland obenland commented Aug 6, 2026

Copy link
Copy Markdown
Member

A number of places matched a user login or nicename against a list of them using a loose comparison. PHP compares two numeric strings numerically rather than character by character, so two logins that are different strings but equal numbers compared as the same user.

This passes the strict flag to in_array() and uses === in the equivalent scalar comparisons, so an identity only matches on an exact string.

Both operands are strings everywhere this applies — the lists come from $wpdb->get_col(), and the needles from WP_User — so nothing that matched before stops matching.

Changed

  • plugin-directory/class-capabilities.php — committer check
  • plugin-directory/api/routes/class-plugin-committers.php — last-committer guard
  • plugin-directory/admin/tools/class-author-cards.php, admin/metabox/class-author-card.php
  • support-forums/inc/class-directory-compat.php — author/contributor/support rep checks, and the support rep back-compat check, which also compared against a slug that can be null
  • support-forums/inc/class-stickies-compat.php — same three checks
  • wporg-bbp-user-badges/inc/class-plugin.php — author/contributor/support rep badges
  • wporg-gp-customizations/inc/class-plugin.php — GTE lookup, already safe as an address is never numeric, changed for consistency
  • themes/pub/wporg-login/pending-create.php — logged-in guard

The contributor check in Capabilities::map_meta_cap() already passed the strict flag; this brings the surrounding checks in line with it.

Deliberately left alone: comparisons of $user_id against $post->post_author. Those compare an int against a string from the database and rely on coercion.

Tests

Capabilities_Committer_Identity_Test covers the committer check and the author fallback used when a published plugin has no committer rows, asserting both that unrelated identities are refused and that genuine committers keep access.

Run with npm run plugins:test from environments/. Full suite passes at 164 tests.

The test extends PHPUnit's TestCase rather than WP_UnitTestCase, because the bundled WordPress test case calls PHPUnit\Util\Test::parseTestMethodAnnotations(), which PHPUnit 10 removed. That is also why the three existing WP_UnitTestCase files are excluded in phpunit.xml. Worth its own ticket.

🤖 Generated with Claude Code

Several checks matched a user login or nicename against a list using a
loose comparison. PHP compares two numeric strings numerically rather
than character by character, so logins that are different strings but
equal numbers matched each other.

Pass the strict flag to `in_array()` and use `===` in the equivalent
scalar comparisons, so identities only match on an exact string. Both
operands are strings in every case: the lists come from `get_col()`
and the needles from `WP_User`.

The contributor check in `Capabilities::map_meta_cap()` already did
this; this brings the surrounding checks in line.

Adds coverage for the committer check, including the author fallback
used when a published plugin has no committer rows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 6, 2026 19:17
@bazza bazza closed this in 6e29a0e Aug 6, 2026
@obenland
obenland removed the request for review from Copilot August 6, 2026 19:51
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.

1 participant