ProtemKey

How passwords are attacked · 5 min read

How data breaches expose passwords

A leaked database is not automatically a list of passwords. How the site stored them decides how much work an attacker faces.

News of a breach usually arrives as a headline with a large number of accounts in it. What that means for any one password depends on a detail the headline rarely mentions: the form in which the site stored passwords before they leaked. This guide walks through what an attacker receives, what they then have to do, and why the same breach can be trivial for one password and hopeless for another.

What leaks

When attackers copy a site’s user table, they typically get a row per account: an identifier such as an email address, sometimes a name or other profile data, and a password field. A well-run site never stores the password itself in that field. It stores something derived from it, so that it can check a login without keeping the secret.

The possibilities, from worst to best, look like this:

How the site stored it What the attacker gets Work needed per password
Plain text The password itself None
Reversible encryption Ciphertext, plus the key if it was stored nearby None once the key is found
Fast hash, no salt (MD5, SHA-1 class) One hash per password; identical passwords share a hash Guess once, match every account at the same time
Fast hash with a unique salt A hash and a salt per account Guess separately for every account, but quickly
Slow password hash with a salt (bcrypt, scrypt, Argon2, PBKDF2) A hash, a salt and a cost setting per account Guess separately for every account, slowly

The last row is what the standards require. NIST SP 800-63B-4 says: “Passwords SHALL be salted and hashed using a suitable password hashing scheme,” and that the purpose is “to make each password guess more expensive for an attacker who has obtained a hashed password file.” The hashing guide explains how salts and cost factors do that.

A hash is not a lock to pick

A hash function runs one way. Nobody “decrypts” a hash. An attacker recovers a password by guessing: take a candidate, run it through the same function with the same salt, and compare the result with the stored value. If they match, the guess was right.

That has two consequences:

  1. The attacker’s speed is set by how fast the hash function runs on their hardware, and the site chose that function.
  2. The order of guesses matters more than anything else. Attackers start with the passwords people actually use, taken from earlier breaches and word lists, then work outward through variations. A password that sits early in that order falls quickly however it is stored. See what makes a password common.

Worked example: one list, one million accounts

Suppose a site with 1,000,000 accounts leaks its password table. An attacker has a list of the 10,000 most common passwords and wants to know which accounts used one of them. Take the site’s two illustrative offline rates (they are assumptions, not measurements):

Illustrative attack rates used throughout this site. They are order-of-magnitude assumptions, not measurements; real rates vary with hardware, hash settings and defenses.
ScenarioRate (assumed)Situation
Online, rate-limited100 guesses per houra login form that slows down or locks out repeated failures
Offline, slow hash10,000 guesses per seconda stolen database hashed with a deliberately slow, salted scheme (bcrypt class)
Offline, fast hash100 billion guesses per seconda stolen database hashed with a fast unsalted hash (MD5, SHA-1 or NTLM class) on a high-end GPU rig

Case 1: fast hash, no salt. Every account that chose 123456 has the same stored hash. The attacker hashes each of the 10,000 candidates once, 10,000 computations in total, and looks each result up in the leaked table. At 10^11 guesses per second that takes a ten-millionth of a second. Even at the slow rate of 10,000 per second it takes one second. Every account using a listed password is found at once.

Case 2: fast hash, unique salt per account. A salted hash of 123456 is different for every account, so the attacker must try all 10,000 candidates against each account separately: 10,000 × 1,000,000 = 10^10 computations. At 10^11 per second that is 0.1 seconds. Salting alone did not save the common passwords; it only stopped one guess from covering everyone.

Case 3: slow hash, unique salt per account. Same 10^10 computations, but now at 10,000 per second: 10^10 ÷ 10^4 = 1,000,000 seconds, about 11.6 days, just to try the 10,000 most common passwords against every account. That is still within reach for a determined attacker, which is the honest point: slow hashing buys time and raises cost, and common passwords remain the first to fall.

Now consider an account protected by a randomly generated six-word passphrase (77.5 bits). It is not on any list. Under case 3 the crack-time table puts the average at hundreds of billions of years. Under case 1 it is still around 35,000 years on average. A breach exposes the hash; whether that becomes the password depends on how the password was chosen.

What storage cannot protect

Some exposures skip hashing entirely:

  • Plain-text storage or logging. If a site stored passwords in plain text, or wrote them to a log file by mistake, the breach contains the password itself. Strength is irrelevant.
  • Capture at entry. Phishing pages and malware on a device collect the password as it is typed, before any hashing happens. NIST’s appendix on password strength notes that “keystroke logging, phishing, and social engineering attacks are equally effective on lengthy and complex passwords as they are on simple ones.” See phishing and passwords.
  • Reuse. Once a password is recovered from one site, it can be tried on others with no guessing at all. That is credential stuffing.

What happens after a breach

Recovered passwords tend to end up in compilations that are shared and reused. That is why NIST requires services to check new passwords against “passwords obtained from previous breach corpuses” and to refuse matches, and why it says verifiers “SHALL force a change if there is evidence that the authenticator has been compromised.” Public datasets of breached passwords exist so that sites can do this checking; one documented design for querying such a dataset without revealing the password is explained in checking breached passwords with k-anonymity.

Note: You usually cannot tell from outside how a site stored passwords. That uncertainty is the practical reason a unique, randomly generated password per site matters: it limits any one breach to one account, and it is expensive to guess even under the weakest storage.

Summary

  • A breach leaks whatever the site stored. Plain text gives away everything; a salted, slow hash forces the attacker to guess account by account.
  • Guessing goes from most common to least common, so common passwords fall first under every storage scheme.
  • Salting stops one guess covering every account; slow hashing makes each guess cost more. Neither helps a password that is on a common list.
  • A long random password survives even poor storage, and a unique one limits the damage to a single site.

You can compare these storage scenarios for any length and character set with the crack-time calculator.

Sources

  1. NIST SP 800-63B-4, Digital Identity Guidelines: Authentication and Authenticator Management (2025)
  2. OWASP Password Storage Cheat Sheet

General explanation, not advice for a particular situation. Updated 2026-10-31.