REST API hardening: namespace whitelist has no effect, and "Stop user enumeration"

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:

  1. Register a custom REST namespace from a theme or plugin.
  2. Enable “Disable REST API”.
  3. Add the namespace to the allowed list, exactly as registered: no leading or trailing slash, no “wp-json” prefix, one per line. Save.
  4. 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:

  1. Enable “Stop user enumeration” in the REST API section.
  2. 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.

Thanks for the detailed report.

For the REST API whitelist, the issue is the namespace format. In Allow these REST API namespaces, please specify only the first namespace segment:

mytheme

not:

mytheme/v1

After changing it to mytheme, requests to routes registered under mytheme/v1 should be allowed while Disable REST API remains enabled.

Regarding Stop user enumeration, we have tested this behavior but have not been able to reproduce the issue. With the option enabled, unauthenticated access to the WordPress users REST endpoint is blocked as expected.

Please double-check that the REST API Stop user enumeration option is enabled and test the endpoint again. If it still returns 200 and exposes users, please post:

  • a screenshot of the REST API hardening settings
  • the corresponding WP Cerber Activity log entry
  • the exact request URL and HTTP response status

That should give us enough information to see what is different in your setup.