Make WordPress Core

Opened 7 weeks ago

Last modified 7 weeks ago

#64541 new defect (bug)

In GET requests, interfaces containing the `search` parameter can be vulnerable to logic errors triggered by the input `%2500`.

Reported by: nefelibata's profile nefelibata Owned by:
Milestone: Awaiting Review Priority: normal
Severity: major Version: 6.9
Component: REST API Keywords:
Focuses: Cc:

Description (last modified by sabernhardt)

The returned result is incorrect.

Detailed Interaction Log

Operation ID: GET_/tags

--- API Operation ---
Endpoint: /tags
Method: GET

--- API Parameters ---
Path Parameters:
  <none>
Query Parameters:
  - page =  (type: integer)
  - slug =  (type: string)
  - order =  (type: string)
  - exclude =  (type: array)
  - hide_empty =  (type: boolean)
  - post =  (type: integer)
  - context =  (type: string)
  - per_page = per_page=100 (type: integer)
  - search = search=%2500 (type: string)
  - orderby =  (type: string)
  - include =  (type: array)
Request Body Parameters:
  <none>

--- API Request ---
Headers: Accept: application/json
Authorization: ██

Body: <null>

--- API Response ---
Status Code: 200
Headers: Date: Thu, 22 Jan 2026 12:08:04 GMT
Server: Apache/2.4.62 (Debian)
X-Powered-By: PHP/8.2.27
X-Robots-Tag: noindex
Link: <http://localhost/wp-json/>; rel="https://api.w.org/"
X-Content-Type-Options: nosniff
Access-Control-Expose-Headers: X-WP-Total, X-WP-TotalPages, Link
Access-Control-Allow-Headers: Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type
X-WP-Total: 1
X-WP-TotalPages: 1
Allow: GET, POST
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Content-Length: 685
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=UTF-8

Body:
[{"id":259,"count":0,"description":"","link":"http:\/\/localhost\/tag\/misconceptions-tetranitromethane-overbears-nanga-n\/","name":"0012 4819961","slug":"misconceptions-tetranitromethane-overbears-nanga-n","taxonomy":"post_tag","meta":[],"_links":{"self":[{"href":"http:\/\/localhost\/wp-json\/wp\/v2\/tags\/259","targetHints":{"allow":["GET","POST","PUT","PATCH","DELETE"]}}],"collection":[{"href":"http:\/\/localhost\/wp-json\/wp\/v2\/tags"}],"about":[{"href":"http:\/\/localhost\/wp-json\/wp\/v2\/taxonomies\/post_tag"}],"wp:post_type":[{"href":"http:\/\/localhost\/wp-json\/wp\/v2\/posts?tags=259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}]

Change History (4)

#1 @suhan2411
7 weeks ago

I can reproduce this issue. The %2500 value results in a decoded null byte reaching REST search handling, which causes inconsistent query behavior while still returning 200 responses.

Proposed approach: normalize invalid/null byte sequences in REST request sanitization for search parameters, ensuring predictable behavior without changing response codes. I plan to add a PHPUnit test covering %2500 vs empty search equivalence.

Working on a patch + test.

#2 @sabernhardt
7 weeks ago

  • Description modified (diff)

#3 @sabernhardt
7 weeks ago

#64542 was marked as a duplicate.

#4 @sabernhardt
7 weeks ago

From #64542:

Using the parameter search="%25" returned all results.

Note: See TracTickets for help on using tickets.