← All checks
SecurityTypical severity: Medium

WordPress Exposure Scanner

Detects exposed WordPress version, accessible readme.html and user enumeration via the wp-json API.

What it checks

This scanner checks whether your WordPress exposes its version number, whether the readme.html file is accessible, and whether users can be enumerated through the wp-json API. It detects these information leaks typical of WordPress installs.

Why it matters

Knowing the exact WordPress version lets an attacker look up known vulnerabilities for that specific version. A list of usernames also does half the work for them when trying to guess passwords and break into your admin panel.

How to fix it

Keep WordPress and its plugins fully updated, remove or block access to readme.html, and hide the version number. You can use a security plugin or server rules to disable user enumeration via wp-json and to limit login attempts.

How this check works

This check only runs if your site is WordPress, which it detects by looking for wp-content or wp-includes in the HTML of the main page. If they are not there, it does nothing. If they are, it probes three common leaks. First: the <meta name="generator" content="WordPress 6.x"> tag in the HTML, which reveals the exact version (low severity). Second: the /readme.html file that WordPress ships with every install and that also states the version (low). Third: the /wp-json/wp/v2/users route of the REST API; if it responds 200 with JSON containing the slug and name fields, it is handing out the list of users with their login names (medium severity).

Why it matters

WordPress powers over 40% of the web, which makes it the favourite target of automated attacks. Those attacks work in two steps: identify the version and plugins to pick an exploit, then try passwords against the login. The exposed version solves step one. The user list solves half of step two: with each user's slug (which is their login name, not their display name), the attacker only needs the password, and admin, editor or the owner's name gets tried thousands of times a minute. That is why user enumeration is medium severity and the other two are low.

How to fix it

Version in the generator meta

In your child theme's functions.php or in a small plugin of your own:

remove_action('wp_head', 'wp_generator');

Note that the version also shows in the ?ver=6.x parameters of core CSS and JS files. Hiding it completely takes a security plugin; but what really protects you is keeping WordPress updated, not hiding the number.

readme.html

Delete it after every install and update (WordPress recreates it), or block it at the server. In nginx: location = /readme.html { return 404; }. In Apache, in .htaccess: <Files readme.html> Require all denied </Files>. Do the same with license.txt.

User enumeration

Restrict the users route of the REST API to authenticated sessions. Without a plugin, in functions.php:

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;
});

The usual security plugins (Wordfence, Solid Security, All-In-One Security) have an equivalent option. Also close the old enumeration via ?author=1, which redirects to /author/name/, and add attempt limits and two-factor authentication to the login: even if the username leaks, the password alone stops being enough.

Check it is fixed

curl -s https://yourdomain.com | grep -io '<meta name="generator"[^>]*>'
curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/readme.html
curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/wp-json/wp/v2/users

Expected: the first returns nothing; the second, 404 or 403; the third, 401 or 403 (or 404 if you removed the route).

Frequently asked questions

Is it not enough to rename the "admin" user?

It helps against the dumbest attacks, but if the REST API lists users, the new name is discovered in one request. Rename it and close the enumeration.

My theme or a plugin uses the users REST API on the front end.

Rare, but it happens with some author directories. In that case, instead of removing the route, limit the fields it returns (no slug) or restrict it by user capability. Test it in a staging environment first.

Does this check look at vulnerable plugins?

No; it looks at leaks from the base install. Outdated plugins are partly detected in outdated libraries. And if you have WP_DEBUG_LOG enabled, the public file it creates is covered by exposed logs.

Check it on your site

Scan your site free and see if this and 44 other checks pass, with a fix prompt for every issue.

Scan my site free

Related checks