User enumeration is a reconnaissance technique that attackers use to discover valid usernames on your WordPress site. It is typically the first step before a brute-force attack. If an attacker knows your admin username, they only need to guess the password. If they do not know the username, the attack surface is significantly larger. Blocking enumeration forces attackers to guess both the username and the password, making a successful attack much less likely.
How Attackers Enumerate WordPress Usernames
There are several methods attackers use to discover usernames on a WordPress site. Understanding each one helps you know what to protect against.
- Author archive URLs: By default, WordPress creates author archives at
/author/username/. An attacker can visit?author=1,?author=2, and so on. WordPress redirects these to the corresponding author archive URL, which contains the username in plain text. Automated scripts can cycle through author IDs very quickly to build a complete list of usernames. - REST API users endpoint: The WordPress REST API exposes a
/wp-json/wp/v2/usersendpoint that returns a JSON array of all users who have published posts. This includes usernames, display names, and user IDs. No authentication is required to access this endpoint by default. - Login error messages: When you enter an invalid username on the WordPress login page, the error message says something like "The username X is not registered." When you enter a valid username but a wrong password, it says "The password you entered for the username X is incorrect." This difference tells the attacker whether a username exists.
- oEmbed responses: WordPress oEmbed discovery links in the page source can reveal author information when other sites attempt to embed your content.
- XML-RPC: The
xmlrpc.phpendpoint can be used to test username/password combinations through thewp.getUsersBlogsmethod. While this is more of a brute-force vector, it confirms valid usernames through different error responses.
Why User Enumeration Matters for Security
On its own, knowing a username does not compromise your site. But it makes everything else easier for an attacker. Consider a brute-force attack: if the attacker has to guess both the username and password, the number of possible combinations is enormous. If they already know the username is "admin" or "john", they only need to focus on the password. Combined with common password lists, this can lead to a successful breach in minutes rather than years.
Additionally, discovered usernames can be used in targeted phishing attacks. If an attacker knows your admin account is "sarah.johnson", they can craft more convincing social engineering emails.
Block Author Archive Enumeration
Add this code to your theme's functions.php or a custom plugin. It intercepts requests with the ?author=N parameter and redirects them to the homepage instead of revealing the username:
/**
* Block user enumeration via author parameter
*/
function block_author_enumeration() {
if (is_admin()) return;
if (isset($_REQUEST['author']) && is_numeric($_REQUEST['author'])) {
wp_redirect(home_url(), 301);
exit;
}
}
add_action('init', 'block_author_enumeration');This handles the most common enumeration method. The is_admin() check ensures that backend functionality is not affected. The redirect uses a 301 status code, which tells search engines to update their index (in case author archive URLs were previously indexed).
Disable the REST API Users Endpoint
The following code removes the users endpoint from the REST API for visitors who are not logged in. Authenticated users (like admins and editors) can still access it, which preserves functionality for the block editor and other admin tools:
/**
* Remove REST API users endpoint for unauthenticated requests
*/
add_filter('rest_endpoints', function($endpoints) {
if (!is_user_logged_in()) {
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[\d]+)']);
}
}
return $endpoints;
}); After adding this code, unauthenticated requests to /wp-json/wp/v2/users will return a 404 error instead of listing your users.
Sanitize Login Error Messages
WordPress displays different error messages for "invalid username" and "wrong password" scenarios. This reveals whether a given username exists on the site. The fix is simple: return the same generic message for all login failures:
/**
* Use a generic login error message
*/
add_filter('login_errors', function() {
return 'Invalid username or password.';
});With this change, an attacker cannot determine whether a login attempt failed because of a wrong username or a wrong password. Both cases produce the same response.
Remove oEmbed Discovery Links
WordPress includes oEmbed discovery links in the HTML head of your pages. These links can expose author information when other sites attempt to embed your content. Remove them with a single line:
remove_action('wp_head', 'wp_oembed_add_discovery_links');This does not affect your ability to embed content from other sites. It only prevents other sites from auto-discovering embeddable content on your site.
Block Author Enumeration via .htaccess
If you run Apache, you can add a server-level redirect that blocks author enumeration before WordPress even loads. This is more efficient than a PHP-based solution because it does not require PHP processing:
# Block user enumeration via author parameter
RewriteCond %{QUERY_STRING} ^author=\d+ [NC]
RewriteRule .* /? [R=301,L]Place this in your .htaccess file before the WordPress rewrite rules. It catches any request with an author= query parameter containing a number and redirects to the homepage.
Plugin-Based Solutions
If you prefer not to add code manually, several security plugins handle user enumeration prevention:
- Stop User Enumeration: A focused, lightweight plugin that specifically blocks author scans and REST API user listing. Does one thing and does it well.
- iThemes Security (Solid Security): A comprehensive security suite that includes user enumeration protection alongside features like two-factor authentication, file change detection, and brute-force protection. The enumeration blocking is found under the "WordPress Tweaks" section.
- Wordfence: Primarily a firewall and malware scanner, but its firewall rules can block enumeration attempts. The free version includes basic protection; the premium version adds real-time firewall rules.
- All In One WP Security: A free, beginner-friendly plugin with a user enumeration prevention option under User Accounts > WP Username. Also offers a firewall and login lockdown features.
Test Enumeration on Your Own Site
Before and after implementing these protections, you should test whether enumeration still works. Here is how:
- Author archive test: Open a private browser window and visit
https://yoursite.com/?author=1. If protection works, you should be redirected to the homepage instead of seeing an author archive page with the username in the URL. - REST API test: Open
https://yoursite.com/wp-json/wp/v2/usersin your browser while not logged in. You should see a 404 error or an empty response, not a list of users with their usernames. - Login page test: Try logging in with a username that does not exist, then try with a real username but a wrong password. Both should produce the same error message.
- InspectWP scan: Run a new InspectWP scan of your site. The security section checks for user enumeration vulnerabilities and will indicate whether your protections are working correctly.
Additional Hardening Tips
User enumeration prevention works best as part of a broader security strategy. Consider these complementary measures:
- Avoid "admin" as a username: If your admin account is still named "admin", create a new administrator account with a unique username, assign all content to it, and then delete the old "admin" account.
- Use strong, unique passwords: Even if an attacker discovers a username, a strong password makes brute-force attacks impractical. Use a password manager to generate and store complex passwords.
- Enable two-factor authentication: 2FA adds a second layer of protection. Even if both the username and password are compromised, the attacker still cannot log in without the second factor.
- Limit login attempts: Plugins like Limit Login Attempts Reloaded or Loginizer can lock out IP addresses after a set number of failed login attempts.