WordPress makes it easy, by design, to find usernames. The REST API exposes a public /wp-json/wp/v2/users endpoint that returns a list of all registered authors including their display names and slugs. The URL pattern /?author=1 redirects to the author archive for user ID 1, typically your first admin account, revealing their username in the URL. Attackers use both of these methods in automated reconnaissance before launching credential brute-force attacks, because knowing the exact username cuts the work in half.
The Code
This snippet addresses both enumeration paths. Add it to your functions.php or a site-specific plugin.
Blocking the REST API Endpoint
The rest_endpoints filter receives an array of all registered REST API routes. The snippet removes the /wp/v2/users and /wp/v2/users/(?P<id>[d]+) routes when the current request is not from a logged-in user. Authenticated requests, from the block editor, REST API clients using application passwords, or your own admin tools, are unaffected. Only unauthenticated public access is blocked.
This approach is preferable to disabling the REST API entirely, which breaks the block editor, WooCommerce, and a large number of modern plugins that depend on REST API access.
Blocking Author Archive Enumeration
The second block hooks into init and checks for a numeric author query parameter in the request. If found and the current user doesn’t have the list_users capability (which requires administrator or editor role), the request is redirected to the homepage with a 301. This prevents the /?author=1 redirect from completing, which means the username never appears in the URL.
The ! is_admin() check ensures this doesn’t interfere with admin-side requests where author parameters are used legitimately.
Testing the Fix
After adding this snippet, open an incognito window and visit yourdomain.com/wp-json/wp/v2/users. You should receive a 404 response rather than a JSON list of users. Also test yourdomain.com/?author=1, it should redirect to your homepage rather than to an author archive URL containing a username.
Tools like WPScan use both of these vectors by default in their user enumeration module. Running a scan against your own site before and after applying this snippet is a useful way to confirm it’s working as expected.
Display Names vs Usernames
One important note: this snippet blocks enumeration of login usernames through automated means, but it doesn’t prevent users’ display names from appearing in post bylines, comment sections, or author archive page titles. If a user’s display name matches their login username, which is WordPress’s default, their login credential is still effectively public. Encourage all authors to set a display name different from their login username under Users → Profile → Display name publicly as.
// Block unauthenticated access to the REST API users endpoint
add_filter( 'rest_endpoints', function( $endpoints ) {
if ( ! is_user_logged_in() ) {
unset( $endpoints['/wp/v2/users'] );
unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
}
return $endpoints;
} );
// Prevent user enumeration via ?author=N URL redirect
add_action( 'init', function() {
if (
! is_admin() &&
isset( $_REQUEST['author'] ) &&
! current_user_can( 'list_users' )
) {
wp_redirect( home_url( '/' ), 301 );
exit;
}
} );
