WordPress breached password check: what leaves your site
A password can be long, mixed and unusual and still be on a list of passwords published after a breach. Length rules cannot see that. A breached password check can, by comparing a new password with those published lists as it is chosen.
The obvious worry is sending passwords somewhere. BetterShield’s check never does. This guide explains how the WordPress breached password check works, what leaves your site and what does not, which passwords it checks, and what happens to the passwords people already use.
Quick summary
- Refuse passwords found in known breaches is a fix under Signing in on BetterShield › Protect › Login & Access. It is off until you turn it on.
- It asks Have I Been Pwned’s Pwned Passwords service. Only the first five characters of a one-way hash leave your site, and the comparison happens on your server.
- It checks a password when someone signed in chooses one: on a profile, a store’s account page, or through the REST API.
- Passwords already in use are never refused, reset or reported, and signing in is never affected.
- If the service cannot be reached, the password is allowed and the activity log says the check did not run.
What a WordPress breached password check does
BetterShield’s own description puts it plainly: “A password can be long, mixed and unique-looking and still be on a published list.” A password that has been published is one that can be tried anywhere, whatever its length.
So the check asks one question about a new password: has this exact password appeared in a published breach? If it has, the form refuses it with one sentence: “This password appears in a published breach. Choose a different one.” If it has not, the check says nothing at all.
It works alongside BetterShield’s password policy under Settings › General, which sets minimum lengths and refuses passwords built from the username, the site name or very common words. The policy runs first, so a password it refuses never causes a request to leave the site. See General settings.
How the check works: what leaves your site and what does not
Pwned Passwords is a service by Have I Been Pwned that lets a site check a password against published breaches without sending it. Here is the exchange, step by step.
- On your server, the new password is turned into a one-way SHA-1 hash: a fixed string of letters and numbers made from it.
- Five characters leave the site. Only the first five characters of that hash are sent to api.pwnedpasswords.com.
- Many answers come back. The service returns every published hash that starts with those five characters, several hundred of them. BetterShield asks for the answer to be padded to a fixed size, so its length reveals nothing either.
- The comparison happens on your server. BetterShield looks for the rest of the hash in that list. A match means the password has been published.
What is never sent: the password, the account name, the email address, the site address or any identifier. The request names BetterShield and its version, and nothing about your site.
What is never stored: the password, its hash, or the five characters that were sent. BetterShield keeps the service’s public answer for five minutes, so fixing a typo on the same form does not ask again, and even that is filed under a key derived from the five characters rather than the characters themselves.
A person waits on the form while this runs, so the request gives up after five seconds. If the service does not answer, the password is allowed. The log records “Password list check could not be made”, at most once an hour, so a quiet log never passes for a clean one. What BetterShield contacts lists this service with the others.
Which passwords it checks
The check runs only when someone signed in chooses a password:
- The profile screen: changing your own password, or an administrator setting one for another account or a new one.
- A store’s account page, where customers change their password.
- The REST API: an account created or changed through WordPress’s users route or a store’s customers route.
- A password reset completed by someone who is signed in.
It does not check:
- Public registration or reset forms filled in by a signed-out visitor. In the fix’s words, “A visitor’s registration or reset form never waits on an outside service.”
- The store checkout.
- WP-CLI and importers, so a setup script never waits on an outside service.
- Application passwords, which WordPress generates itself.
What happens to passwords already in use
Nothing. The fix is clear about it: it “Never affects signing in, and never refuses, resets or reports a password an account already has.”
That is deliberate. Checking a password someone already has would mean checking it as they sign in, and nobody should be kept out of their own account by a list. Instead, the check applies the next time each person chooses a password.
If you want existing passwords replaced sooner, ask people to change them. BetterShield’s password policy also flags accounts that signed in with a password below the current policy, as the finding Some accounts signed in with passwords below the policy, without forcing a reset. See Score and findings.
How to turn on the breached password check
- Open BetterShield › Protect › Login & Access and find Refuse passwords found in known breaches under Signing in.
- Press Preview the change to read what it will do. Nothing changes.
- Turn the switch on. Because it sits with the sign-in fixes, BetterShield first checks that your recovery link or printed recovery codes work; see Locked out if that check asks you to.
Once it is on, the row reads: “Checked when somebody signed in sets or changes a password. Signing in is never affected.” If another plugin already checks passwords on the same forms, the row says so before you apply it. To stop the check, turn the switch off; nothing else changes. wp bettershield harden breached_passwords --dry-run previews it from the terminal (WP-CLI commands).
What the activity log shows
Two rows belong to this check:
- “Password refused: it appears in a published breach”, rated Low, naming the account that was choosing it. Not the password, not its hash, and not how many times it has been published.
- “Password list check could not be made”, at most once an hour, when the service could not be reached.
Read both together. Several refusals for one account suggest its owner keeps reaching for passwords from published lists, which is worth a friendly word. A run of “could not be made” means the check was not answering, and passwords went through unchecked. See Activity log.
Common mistakes
- Expecting it to check existing passwords. It checks new ones only. Ask people to change theirs if you want them checked.
- Expecting it on a public sign-up form. Signed-out visitors are not checked, so nobody waits on an outside service from a public page.
- Reading a quiet log as all clear. If “Password list check could not be made” appears, the check was not answering for that hour.
- Turning off the password policy. The policy runs first and costs no outside request. Keep both.
Frequently asked questions
Does the breached password check send my password anywhere?
No. The password is hashed on your server and only the first five characters of the hash are sent. The comparison with the published list happens on your server.
Is Pwned Passwords the same as Have I Been Pwned?
Pwned Passwords is a service run by Have I Been Pwned. BetterShield uses only its password range service, and sends it no email address or account name.
Will it lock anyone out of WordPress?
No. It never touches signing in. It only refuses a new password as it is chosen, and allows the password whenever the service cannot be reached.
Does it slow down my site?
Visitors never wait on it. It runs only when a signed-in person sets a password and waits at most five seconds. If the service does not answer, BetterShield waits a minute before asking it again.
Conclusion
A WordPress breached password check closes a gap length rules cannot see, and done this way it never sends a password or touches signing in. Turn on Refuse passwords found in known breaches, keep the password policy beside it, and let each password be checked the next time it changes.
BetterShield is free on WordPress.org. The Hardening guide covers this fix with the other sign-in fixes.