Title: REST API hardening: namespace whitelist has no effect, and “Stop user enumeration” does not block /wp/v2/users (9.9.5, Legacy mode, root install)
Environment
- WP Cerber Security 9.9.5, Legacy mode
- WordPress 7.1
- PHP 8.3 (CloudLinux alt-php), LiteSpeed, shared hosting
- WordPress Address and Site Address are identical, no subdirectory
- No other security plugin installed
Two separate issues in Hardening > WordPress REST API access. Both were verified from a machine outside the server, unauthenticated. Requests originating from the server itself over SSH can take a different path and are not a valid test; likewise, testing while logged in as an administrator always passes because “Allow logged-in users” is enabled.
=== Issue 1: whitelisted namespaces are still denied ===
Settings:
- “Disable REST API” = ON
- “Allow these REST API namespaces” contains, one per line: mytheme/v1 oembed wp-site-health
The theme registers two routes under mytheme/v1. Both are denied for unauthenticated visitors even though the namespace is whitelisted.
Steps to reproduce:
- Register a custom REST namespace from a theme or plugin.
- Enable “Disable REST API”.
- Add the namespace to the allowed list, exactly as registered: no leading or trailing slash, no “wp-json” prefix, one per line. Save.
- From outside the server, unauthenticated: curl -s -o /dev/null -w “%{http_code}\n”
https://example.com/wp-json/mytheme/v1/some-route
Expected: 200 Actual: 403
Turning “Disable REST API” off returns 200 immediately, with nothing else changed. The namespace text was retyped by hand to rule out stray whitespace or non-ASCII characters; no difference. Emptying “Allow REST API for these roles” made no difference either, which is expected since the request carries no session.
The Activity log records these as “REST API request denied” with reason “Access denied by the plugin configuration”. No RID is generated, which per your documentation points to the hardening rules rather than the Traffic Inspector or the anti-spam engine.
This may be long-standing. A user reported the same symptom in April 2024 with a different custom namespace: https://wordpress.org/support/topic/in-this-case-what-is-allow-namespace/ That thread was self-marked resolved without any explanation of what changed, and received no reply from the team.
Practical impact, in case it helps prioritise: our contact form fetches its nonce from a custom REST route, because the site uses full-page caching and a nonce printed into the HTML would be stale by the time a visitor submits. With that route denied, no visitor could submit the form at all. The property filters use a second route on the same namespace and were equally broken.
The knock-on effect was worse than the direct one. Each denial counted as suspicious activity, and the accumulated count triggered automatic IP lockouts against ordinary visitors browsing the public site. A single normal browsing session generated ten or more denials, so legitimate users were being locked out of the whole site within minutes. Since those lockouts are temporary and expire on their own, they had already disappeared from the Access Lists by the time we went looking for them, which made the initial diagnosis considerably harder.
=== Issue 2: “Stop user enumeration” does not block /wp/v2/users ===
Settings:
- “Stop user enumeration” (REST API section) = ON
- “Allow access to user data via REST API for these roles” = Administrator, plus two custom roles
Steps to reproduce:
- Enable “Stop user enumeration” in the REST API section.
- From outside the server, unauthenticated: curl -s https://example.com/wp-json/wp/v2/users
Expected: 401 or 403 Actual: 200, with a JSON array exposing the administrator account. The “name” field contains the actual user_login, not the display name.
Emptying the roles field makes no difference.
Note that the identically named option under “WordPress hardening” works correctly on the same install: ?author=1 returns 404 as expected. Only the REST API section option fails. Two options with the same label in different sections behaving differently is itself a source of confusion when troubleshooting.
This resembles CVE-2022-4417, fixed in 9.3.3, where the users endpoint was not properly blocked. That report was specific to installs in a subdirectory. This install is at the domain root, with WordPress Address and Site Address identical, so it appears to be a different or broader failure rather than that same case.
=== What we did in the meantime ===
Disabled “Disable REST API” so the site would work, and implemented the user endpoint restriction in a small must-use plugin using the rest_endpoints filter. We would rather rely on the plugin’s own option once this is sorted out.
Happy to provide further detail, run tests, or try a patch.