REST API: Validate and sanitize every consumed route parameter - #738
REST API: Validate and sanitize every consumed route parameter#738obenland wants to merge 4 commits into
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the 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. |
95aaea7 to
4fbee73
Compare
|
All new test files now pass the full 🤖 Generated with Claude Code |
4fbee73 to
048f135
Compare
PHPUnit discovers test classes by deriving the class name from the file basename, and PHP class names cannot contain hyphens, so test files can never satisfy the hyphenated-lowercase file name sniff. WordPress core carries the same exemption for its test suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPDKVeVpBoWoB8euRB5hK2
94a04cf to
c38c4ca
Compare
Several plugins/v1 routes consumed request parameters that were never declared in their route registration, leaving them without validation or sanitization: query-plugins fed eleven undeclared parameters into WP_Query, update-stats iterated an untyped body parameter, and locale values reached switch_to_locale() unchecked. Declares every consumed parameter with types, requirements, and validate/sanitize callbacks, moving URL placeholder args to shared route-level declarations. Adds functional test suites for each endpoint, exercising queries, stat updates, slug changes, scan callbacks, and access control end-to-end. The tests also surfaced that the plugin information endpoint emitted warnings when review data is unavailable, now guarded in get_plugin_reviews_markup(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPDKVeVpBoWoB8euRB5hK2
The themes/1.x query, info, and tags endpoints passed all request parameters into Themes_API without route-level declarations, the public stats endpoints consumed an undeclared startDate, update-stats iterated an untyped body parameter, and the preview-blueprint POST route persisted an undeclared blueprint payload. Declares every consumed parameter with types and validate/sanitize callbacks, and fixes two 'required' => 'true' string typos. Adds functional test suites for each endpoint, exercising theme queries, information lookups, tags, stats, stat updates, blueprints, and access control end-to-end. The tests also surfaced that the info endpoint's 404 handling checked a nonexistent property and never fired, now reading the error from the API response. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPDKVeVpBoWoB8euRB5hK2
The route consumed the page placeholder and the isTyping flag without declaring them, leaving the unconstrained URL capture without a sanitizer at the route layer. Declares page as a required, sanitized route-level argument shared by all three methods, and types isTyping as a boolean on the POST handler. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JPDKVeVpBoWoB8euRB5hK2
c38c4ca to
b929d15
Compare
An audit of every `register_rest_route()` call in the repo found 22 route registrations whose callbacks consume request parameters that were never declared in an `args` schema, leaving them without validation or sanitization at the route layer. The wporg-login routes were already fixed in r15003; this PR closes out the rest.
Two validation postures are used deliberately:
Plugin Directory
Theme Directory
Also Viewing (support forums)
Coding standards
New test files pass the full `--standard=WordPress` ruleset with one structural exception: PHPUnit derives test class names from file basenames and class names cannot contain hyphens, so test files can never satisfy the hyphenated-lowercase filename sniff (renaming them makes PHPUnit silently skip every test). `phpcs.xml.dist` now carries the same tests-scoped exemption WordPress core uses.
Tests
One functional test suite per endpoint file (18 test files plus a shared base class per directory, loaded from each suite's bootstrap), testing what the endpoints do: querying finds published plugins and honors the `slug:` bypass and pagination, the info endpoints return plugin/theme data, update-stats writes whitelisted meta and skips unknown slugs and malformed entries, the tags endpoint lists and slices tags, slug changes work for plugin authors and reject invalid slugs, blueprints are generated for themes, gandalf callbacks are recorded, and every gated endpoint enforces its bearer token or capability check. Malformed-input behavior is pinned per posture: coercion on the proxied routes, 400s on the strict ones.
Writing these surfaced two dormant bugs, fixed here: the theme info endpoint's 404 branch read a nonexistent `$api->error` property so unknown themes returned 200 (now reads the error from the API response), and the plugin info endpoint emitted PHP warnings when review data is unavailable (now guarded in `get_plugin_reviews_markup()`).
Known limitations, deliberately out of scope: the upload endpoint's real inputs (`$_FILES['zip_file']`, `$_POST['comment']`, `$_REQUEST['upload_token']`) are read from superglobals inside `Upload_Handler` and are invisible to route schemas — declaring them without changing the read path would be decorative; and api.wordpress.org's 48-hour negative caching of failed internal `plugin_information` dispatches (`class-plugins-info-api.php`) predates this PR and deserves its own change.
Both suites pass under wp-env with no warnings: plugin-directory 191 tests, theme-directory 40 tests.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JPDKVeVpBoWoB8euRB5hK2