Skip to main content

Ports

WordPress REST API user enumeration: what it leaks, and the exact fix.

Published 2026-06-08 · Last updated 2026-06-08 · Vantyris editorial

Visit /wp-json/wp/v2/users on most WordPress sites and you'll get back a JSON array with the public slug of every account that has authored a post. Those slugs are usually the login names. Attackers feed them into credential-stuffing and password-spray tools that hammer /wp-login.php. The endpoint is meant to be public (WordPress uses it to render author archives), but a small-business site rarely needs that, and locking it down is a one-filter PHP edit.

What this means for your business

How to fix

Add a rest_endpoints filter that unsets the /wp/v2/users endpoint for unauthenticated requests. It's a five-line snippet in your theme's functions.php or in a small must-use plugin.

  1. Decide where to put the code. If you have a child theme, use its functions.php, which survives core theme updates. Otherwise create a tiny must-use plugin at wp-content/mu-plugins/disable-user-rest.php, containing a <?php opener and the snippet. Must-use plugins survive theme changes too.
  2. Drop in the filter. Paste the following. The unset on the regex version handles requests like /wp/v2/users/1. Without it, attackers can still walk users by ID. add_filter('rest_endpoints', function ($endpoints) { if (isset($endpoints['/wp/v2/users'])) { unset($endpoints['/wp/v2/users']); } if (isset($endpoints['/wp/v2/users/(?P<id>[\d]+)'])) { unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']); } return $endpoints; });
  3. Verify the fix. Open https://your-site/wp-json/wp/v2/users in an incognito browser. You should get a 404 or 401 response, not a JSON array. Then try https://your-site/?author=1. If your site still 301-redirects to /author/<slug>/, you also need to block the classic enumeration path (see the gotcha below).
  4. Re-scan to confirm. Run a Vantyris scan after the change. The wp.rest_users_endpoint_protected healthy signal should appear. If the finding still shows as wp.rest_user_enum, something else is exposing users. Check Wordfence, or a cache layer that might be serving a stale 200 from before the change.

Owner: Your web developer or whoever maintains the WordPress theme. · Time: About 30 minutes including verification.

Common gotchas

How to verify the fix

From a browser in incognito mode (no cookies, not logged in), open /wp-json/wp/v2/users. The healthy result is 401, 403, or 404, meaning anything other than a JSON array of user objects. Also confirm /wp-json/wp/v2/users/1, /wp-json/wp/v2/users/2, and /?author=1 all return non-200 responses. Re-running a Vantyris scan records the closure as an audit-trail row.

Cyber Essentials alignment

This finding informs the following Cyber Essentials control areas (the UK government's baseline scheme, a sound checklist in any country):

Vantyris is not a CE certifying body. The mapping above is informational.

Common follow-up questions

Does this break anything on my front-end?

Almost never. Author archives render from server-side queries, not from the REST API. Subscription forms, contact forms, and most page-builder plugins don't touch this endpoint either. If you have a custom React or single-page front-end that authenticates to WordPress and reads users, that integration breaks. Switch it to rest_authentication_errors so authenticated reads still work.

Should I just install Wordfence and skip the code edit?

Wordfence (free tier) has a one-click toggle that does essentially the same thing. If you already run Wordfence, use it. That's the faster path. The code version above is for sites that don't want another full plugin for this one fix.

Will this stop brute-force attacks against /wp-login.php?

It removes the source of the username list. It doesn't stop the brute-forcing itself. For that you need rate-limiting (Wordfence, iThemes), a WAF rule on /wp-login.php, and account-level 2FA. Locking down the endpoint is one layer of defence. The others sit on the login page itself.

Why isn't this disabled by default in WordPress?

The endpoint is part of the REST API contract, and WordPress's headless / Gutenberg / Jetpack functionality assumes it's there. Disabling it by default would break too much. The core team's position is that exposing public author slugs isn't a vulnerability. Whether to treat it as recon is the site owner's call.

References

Related explainers

Want Vantyris to check your domain for this and 196 other problems?

The teaser scan is free and needs no card. A verified scan starts at $10€10£10A$15¥1,500AED 40 and comes with the workspace: finding workflow, score trend, three PDF layouts, share links and monitoring.

Written by Vantyris