Take the MD5 hash of "password123": 482c811da5d5b4bc6d497ffa98491e38. Paste that string into Google. You'll get the original password back from at least half a dozen sites.
This isn't a vulnerability in MD5. It's a lookup table. Somebody precomputed the MD5 hash of every common password, dictionary word, and common variation, then indexed them. The search engine just queries that index. This works for any deterministic hash function that doesn't use a salt.
Why this happens
MD5 is deterministic. The same input always produces the same output. That means "password123" has one MD5 hash, everywhere, forever. If you know what hash corresponds to "password123" — which is trivially easy to compute — you can build a table mapping hashes back to passwords and look up any hash you encounter.
These tables have existed for decades. Sites like CrackStation and hashes.com have pre-built tables covering billions of common passwords. The hash you're trying to protect might already be in there.
Salting makes this impossible
A salt is a random value — usually 16 to 32 bytes — that gets mixed into the password before hashing. Two users with identical passwords get different salts, so they get different hashes. The salt is stored in plaintext alongside the hash, because the point isn't secrecy — it's uniqueness.
If you hash "password123" with the salt x7kQ9mP2 and store both, an attacker with your database can't look the hash up anywhere. They'd have to build a lookup table from scratch for that specific salt, which destroys the economics of precomputed attacks.
A properly salted hash of "password123" looks like nothing in the lookup tables. The hash is unique to that one user in your database.
Why breach dumps still contain plain MD5
Because a lot of software, especially older PHP applications, stored passwords as md5($password) with no salt. These apps were often written in the early 2000s when this was a commonly accepted approach, before the consequences were well understood. Once those databases were breached, the hashes cracked immediately.
RockYou (2009, 32 million accounts, plaintext passwords). LinkedIn (2012, 117 million SHA-1 hashes). Adobe (2013, 153 million accounts, 3DES with no salt). The combination of fast hash functions and no salting meant that breaches turned into plaintext password dumps within hours.
What this means if you're building something today
Never hash passwords with MD5, SHA-1, or SHA-256 directly. They're too fast and the determinism problem doesn't go away with a modern hash function — it just gets marginally harder to precompute tables for.
Use bcrypt, Argon2id, or scrypt. These are specifically designed for passwords. They're slow by design, they include salting automatically, and they include the parameters in the output so you can verify old hashes even after raising the cost.
The MD5 tool here is useful for checksums and verifying file integrity. For anything involving passwords, use the bcrypt tool instead — and notice that the same input produces different output each time, because the salt is generated fresh on every hash.