Opened 13 hours ago
Last modified 13 hours ago
#66385 new defect (bug)
Check for a non-string _method parameter in WP_REST_Server::serve_request()
| Reported by: | josephscott | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | REST API | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests |
| Cc: | Focuses: |
Description
WP_REST_Server::serve_request() lets the _method query parameter override the request method. It only checks that _method is set ( GH ) and then passes it to WP_REST_Request::set_method(), which calls strtoupper() on it ( GH ). A string like ?_method=POST works fine, but ?_method[]=POST makes it an array. This happens before routing, so any REST API URL can reach it.
You can easily create a PHP fatal error by sending an array:
$ curl -g -i 'localhost:8889/wp-json/?_method[]=POST'
HTTP/1.1 200 OK
Server: nginx/1.29.7
Date: Mon, 26 Oct 2026 21:14:49 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.3.30
X-Robots-Tag: noindex
Link: <http://localhost:8889/wp-json/>; rel="https://api.w.org/"
X-Content-Type-Options: nosniff
<br />
<b>Fatal error</b>: Uncaught TypeError: strtoupper(): Argument #1 ($string) must be of type string, array given in /var/www/src/wp-includes/rest-api/class-wp-rest-request.php:206
Stack trace:
#0 /var/www/src/wp-includes/rest-api/class-wp-rest-request.php(206): strtoupper(Array)
#1 /var/www/src/wp-includes/rest-api/class-wp-rest-server.php(439): WP_REST_Request->set_method(Array)
#2 /var/www/src/wp-includes/rest-api.php(496): WP_REST_Server->serve_request('/')
#3 /var/www/src/wp-includes/class-wp-hook.php(369): rest_api_loaded(Object(WP))
#4 /var/www/src/wp-includes/class-wp-hook.php(393): WP_Hook->apply_filters('', Array)
#5 /var/www/src/wp-includes/plugin.php(582): WP_Hook->do_action(Array)
#6 /var/www/src/wp-includes/class-wp.php(417): do_action_ref_array('parse_request', Array)
#7 /var/www/src/wp-includes/class-wp.php(877): WP->parse_request('')
#8 /var/www/src/wp-includes/functions.php(1375): WP->main('')
#9 /var/www/src/wp-blog-header.php(16): wp()
#10 /var/www/src/_index.php(17): require('/var/www/src/wp...')
#11 /var/www/src/index.php(19): require_once('/var/www/src/_i...')
#12 {main}
thrown in <b>/var/www/src/wp-includes/rest-api/class-wp-rest-request.php</b> on line <b>206</b><br />
WordPress needs to check that _method is a string before using it to override the request method. Instead of a HTTP 200 the response should be 400 Bad Request with JSON data indicating it what the error is.
I have a PR to address this.
Change History (1)
This ticket was mentioned in PR #14901 on WordPress/wordpress-develop by @josephscott.
13 hours ago
#1
- Keywords has-patch has-unit-tests added
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
…uest()
See https://core.trac.wordpress.org/ticket/66385
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Opus 5.5
Used for: Review, confirmation, and final details on the src/ changes. Claude wrote the test code.