Repository navigation
Users: Prevent non-numeric searches from matching user IDs in WP_User_Query. - #15262
abhishekfdd wants to merge 1 commit into
Conversation
…_Query. When `ID` was included in `search_columns`, the search term was compared using `ID = %s`. MySQL casts the string to a number for that comparison, so a search such as `123abc@example.com` matched the user with ID 123. The ID column is now only compared when the search term is a plain non-negative integer string. If no other columns remain to be searched, an always-false condition is used so that no users are returned, rather than all users. Includes unit tests. See #57731.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
When
IDis insearch_columns,WP_User_Query::get_search_sql()buildsID = %swith the raw search term. MySQL casts the string to a number for that comparison, using only its leading digits, so'123abc@email.com'becomes123. As a result, an email lookup such as:returns user 123 even when no user has that email address. Code that uses this to resolve an email to an account can silently get a different user.
Change
IDcomparison is only added when the search term (after whitespace and the*wildcards are trimmed inprepare_query()) is a plain non-negative integer string, checked withctype_digit().is_numeric()is not used because it accepts1e3,12.5,-5,+5and whitespace-padded values, all of which MySQL would also cast.IDwas requested and the term is not an integer), the method returnsAND 1=0, so the query matches no users. It does not drop the search clause, which would return every user.search_columnsis not passed is unchanged. Note that for terms like1e3or5.0, which passis_numeric(), auto-detection still selectsuser_loginandID, butIDnow no longer matches them through MySQL's cast.SQL before
SQL after
Leading zeros (
0123)0123is still treated as ID 123. It is an unambiguous integer with no other meaning in a digits-only string, and this is the behaviour MySQL already gives (ID = '0123'). Rejecting it would be a behaviour change that does not fix any mismatch. The value is still bound with%s, so a very long digit string never overflows toPHP_INT_MAXthe way an(int)cast or%dwould.Side effect
If a
user_search_columnsfilter returns an empty array, the method previously builtAND (), which caused a database error. It now buildsAND 1=0. The result is the same (no users), without the error.Testing
Automated tests:
npm run test:php -- --group 57731. These cover:['user_email', 'ID']returns no usersIDonly with a non-numeric search returns no users (not all users)['ID']matches, including0-prefixed and*wildcard variants*wildcards%de0,%d.0,%d.5,-%dand+%dinputs (built from the user's real ID) do not match by ID. Thee0,.0and+variants do match on trunk.search_columns(auto-detection) still matches by ID21 of the 27 new tests fail on trunk. The full
usergroup passes on both single site and multisite.Manual testing:
wp eval 'var_dump( ( new WP_User_Query( array( "search" => "1abc@example.com", "search_columns" => array( "user_email", "ID" ), "fields" => "ID" ) ) )->get_results() );'array(1) { [0]=> string(1) "1" }. After:array(0) {}.Sibling query classes (
WP_Comment_Query,WP_Site_Query,WP_Network_Query) were checked. They only useLIKEinget_search_sql(), so they are not affected.Trac ticket: https://core.trac.wordpress.org/ticket/57731
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: Reproducing the bug, implementing the fix and tests, and drafting this description, following my step-by-step instructions.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.