Stop user enumeration in WordPress without a plugin
Close the common ways to list your user names with one Snipfire snippet. Stop User Enumeration adds logging and more options; here is what each covers.
What Stop User Enumeration does
Stop User Enumeration blocks attempts to find your user names and can log them so a tool like fail2ban can block the visitor. The plugin on WordPress.org
What the snippet does the same
- Addresses like ?author=1 no longer reveal a user name to visitors who aren't logged in. The snippet sends them to the home page.
- The REST API users list is hidden from visitors who aren't logged in. Logged-in users, and the block editor, still get it.
- The users sitemap is removed.
What's different
- The plugin logs each attempt with the visitor's IP address, for use with fail2ban. The snippet doesn't log anything.
- The plugin can also remove author details from oEmbed responses and strip numbers from comment author names. The snippet doesn't.
- The plugin has a settings screen to switch each part on or off. The snippet does all three every time.
- The snippet only checks ?author in the address. The plugin also checks form submissions (POST).
When to keep the plugin Keep the plugin if you block attackers with fail2ban or want the oEmbed and comment protections.
The snippet: Stop visitors from listing user names
Closes the usual ways to find your user names: ?author=1 links, the public users list in the REST API and the users sitemap. Logged-in editors still see authors as usual.
<?php
// ?author=1 would redirect to /author/<user-name>/.
add_action(
'template_redirect',
static function () {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checks that the parameter is there.
if ( isset( $_GET['author'] ) && ! is_user_logged_in() ) {
wp_safe_redirect( home_url( '/' ), 301 );
exit;
}
},
1
);
// /wp-json/wp/v2/users lists every author. Keep it for logged-in users (the
// block editor needs it) and hide it from everyone else.
add_filter(
'rest_endpoints',
static function ( $endpoints ) {
if ( ! is_user_logged_in() ) {
foreach ( array_keys( $endpoints ) as $route ) {
if ( str_starts_with( $route, '/wp/v2/users' ) ) {
unset( $endpoints[ $route ] );
}
}
}
return $endpoints;
}
);
// No wp-sitemap-users-1.xml.
add_filter(
'wp_sitemaps_add_provider',
static fn( $provider, $name ) => 'users' === $name ? false : $provider,
10,
2
);
Notes, where it runs and what it was tested with
Switching from the plugin
- Install the snippet in Snipfire (it arrives switched off).
- Deactivate Stop User Enumeration.
- Switch the snippet on. Snipfire checks the code and test-loads your site first.
- Check the page it affects, then delete the plugin.