Pwned Password
Hash Lookup
k-Anonymity breach check β your password never leaves this page
How Pwned Password Hash Lookup Keeps Your Credentials Private While Checking Breach Databases
In 2013, security researcher Troy Hunt found himself manually searching through credential dumps to help people understand whether their passwords had been stolen. A decade later, his HaveIBeenPwned project holds over 900 million compromised passwords β and the method used to query it safely has become a textbook example of privacy-preserving cryptography. That method is called k-anonymity, and understanding it changes how you think about password security entirely.
The Naive Approach and Why It Fails
Before k-anonymity arrived as a solution, the obvious way to check a password against a breach database was simple: send the password to a server, let the server look it up, return an answer. This is exactly what you must never do. Even if the operator of that server has good intentions, you have now handed your password to a third party over the network. If the connection is intercepted, if the server logs requests, or if the service is compromised itself, your credential is exposed. You would be solving a security problem by creating a worse one.
Some early breach-check tools accepted SHA-1 hashes of passwords rather than plaintext, which seems safer at first glance. But it isn't. A 40-character SHA-1 hex string, sent verbatim to an API, is still uniquely identifying. Since most real-world passwords are drawn from a finite dictionary of common choices, an attacker who intercepts hashed lookups can reverse them with a precomputed rainbow table in seconds. Sending the full hash is only marginally better than sending the password itself.
The k-Anonymity Model: Sending Just Enough to Get the Answer
The HIBP range API, launched in 2018 by Troy Hunt in collaboration with Cloudflare, introduced a more elegant solution. Here is how the protocol works step by step.
First, your device computes the SHA-1 hash of your password entirely locally. No network call has happened yet. The password itself and the full 40-character hash both remain in memory on your machine. Next, only the first five hexadecimal characters of that hash β one eighth of the total β are transmitted to the API endpoint at api.pwnedpasswords.com/range/{prefix}.
The server returns every hash in its database that starts with those five characters. On average, this is around 800 entries, each formatted as the remaining 35-character suffix followed by a colon and the number of times that password appeared in breach data. Your browser then compares the full suffix of your locally computed hash against every entry in that list. If it finds a match, it shows you the breach count. If not, you get the all-clear.
The critical insight is that those five characters create a set large enough to hide in. With 16^5 = 1,048,576 possible prefixes, and the HIBP database spread across all of them, any single prefix lookup reveals nothing specific about which password you are checking. An observer on the network sees only that you queried a prefix shared by roughly 800 other passwords. They cannot determine which of those 800 you were actually checking without already knowing your password β which defeats the entire purpose of the attack.
Why SHA-1 and Not SHA-256?
Security-minded developers occasionally raise an eyebrow at SHA-1's use here. SHA-1 is considered cryptographically broken for purposes like digital signatures β collision attacks have been demonstrated, meaning two different inputs can be engineered to produce the same hash. However, for the purpose of a password breach lookup, SHA-1's weaknesses are irrelevant. No one is trying to forge a certificate or spoof a signature. The database simply uses SHA-1 as a consistent identifier, and the k-anonymity model protects against preimage attacks (reversing a hash to find the password) by design β the attacker never receives the full hash in the first place. The HIBP team has also acknowledged this and the database format will likely migrate over time, but for now SHA-1 is the standard all clients must use.
The Add-Padding Header: Defeating Traffic Analysis
A subtle attack vector remains even with k-anonymity: response size. If prefix A typically returns 750 results and prefix B returns 820, an observer who measures the size of the API response can use that as a fingerprint to narrow down which prefix was queried. Over time, correlating response sizes with known prefix sizes could partially de-anonymize lookups.
The HIBP API addresses this with an optional Add-Padding: true request header. When this header is present, the response is padded with fake entries to a consistent size, eliminating the side channel. Well-implemented clients always send this header β and the tool on this page does exactly that.
What the Breach Count Actually Tells You
When a password comes back with a count, the number represents how many times that exact plaintext password appeared across all the breach datasets that HIBP has ingested. A count of 3 means three different credential records contained that password; a count of 3,847,931 means it was password123 or something equally catastrophic.
The threshold for concern is not "greater than zero." Any appearance in the database at all means the password exists in attacker wordlists and will be tried in any credential-stuffing or dictionary attack against accounts that use it. Passwords with counts in the millions are in the very first file any script kiddie downloads. Passwords appearing once may have come from a targeted breach of a small service, but they are still burned. The correct action in either case is the same: stop using that password immediately.
A clean result β not found in the HIBP database β is reassuring but not a guarantee of safety. HIBP is comprehensive but not omniscient. Breaches that have not yet surfaced publicly, credential dumps still circulating in private criminal forums, and very recent incidents may not be reflected. A clean result means "this password is not in the publicly known breach corpus," not "this password is safe forever."
The Browser Crypto API: No Library Required
One architectural decision in this tool worth noting is the use of the native crypto.subtle.digest() method built into modern browsers. This is part of the Web Cryptography API, a W3C standard supported in all major browsers since around 2017. It runs SHA-1 hashing asynchronously in a dedicated cryptographic context, separate from the main JavaScript thread, without any third-party library. There is no CDN dependency, no external script tag, nothing to intercept between the library download and the hash computation. The entire hashing operation is performed by the browser's own implementation.
This matters because supply-chain attacks on JavaScript libraries are a real and growing threat. Even a well-audited npm package can become malicious if its author's account is compromised. A tool that handles password input should minimise its dependency surface to zero wherever possible.
Practical Audit Workflow
Security teams and individuals doing a periodic credential audit can use this tool methodically. Work through your password manager's export, checking each unique password that has been in use for more than six months. Flag anything with a breach count, prioritise accounts by sensitivity (banking, email, and identity providers first), then work down the list. For passwords the tool cannot check β passphrases held only in hardware security keys or credentials for offline systems β the k-anonymity model still suggests good hygiene: change anything older than two years regardless of breach status.
The k-anonymity approach represents a rare case in security engineering where the privacy-preserving solution is also the more technically elegant one. By revealing just enough information to receive a useful answer and nothing more, the protocol turns a potentially dangerous data transfer into something genuinely safe. The password never travels. The full hash never travels. Only five characters go out, and a list comes back β and your browser does the rest.