Blog What the free audit finds Part 7 of 9

Login names are half a login

By default, WordPress lists every author's login name for anyone who asks, so attackers only have to guess the passwords. Four changes close the list without locking anyone out.

Where the list comes from

WordPress has a programming interface that other software uses to read the site: the mobile app, the block editor, and integrations. One part of it lists users. By default anyone can read that list, logged in or not, at your site's address followed by /wp-json/wp/v2/users. It shows each account's public name and its login slug, which on most sites is the login name itself.

There is an older way to get the same information. Add /?author=1 to your site's address and WordPress redirects to the first account's archive page, whose address contains the login name. Try 2, 3 and so on, and you get the rest of your staff.

Why a username matters

A login has two halves. Guessing both is slow. If one half is handed over, all that's left is trying passwords, and password lists from other breaches are cheap. When your usernames are public, each account is protected by its password alone.

The legacy remote interface, xmlrpc.php, speeds up the guessing. One request can carry hundreds of password attempts. It is on by default, and most sites haven't used it since the WordPress mobile app stopped needing it.

Four changes

First, restrict the user list to logged-in visitors. Security plugins offer the setting, and it is a short filter for a developer to add. The block editor and the app still work, because they are logged in.

Second, turn off xmlrpc.php unless a specific integration needs it. Jetpack and a few older mobile tools do. If your site uses one of them, keep it on and put a rate limit in front of it instead.

Third, give every account that can publish a second factor. This is the change that matters most, because it makes a guessed password useless. An authenticator app on a phone is enough. Administrators first, then editors, then everyone.

Fourth, rename or remove the account called admin, and make the display name of each account different from its login name. Neither is a defense on its own. Both remove the easiest guess.

What not to bother with

Moving the login page to a secret address is popular and does little. The user list lives at a different address, so moving the login page doesn't hide it. A plugin that hides the WordPress version number doesn't help here either. Spend the time on the second factor.

What the free audit reports

The free audit requests the user list the same way an attacker would. It reports how many login names came back and shows the first few so you can recognize them. It also reports whether xmlrpc.php is answering. Each finding is moderate on its own and serious in combination, and they usually show up together.

Run the free audit on your site

This check is part of the free audit. Enter your domain to see what it finds on your site.

Public information only. Results in about a minute.