This weakness occurs when a system hashes sensitive data (typically passwords) without adding a unique random value called a "salt" to each hash before processing. Without salt, an attacker can use precomputed tables of common passwords and their hashes to quickly reverse-engineer or match hashed values, bypassing the security that hashing is meant to provide.
02How It Happens
Hashing is designed to be a one-way function: you cannot reasonably reverse it to recover the original input. However, this protection only works if the attacker cannot predict what inputs will be hashed. When the same password is hashed the same way every time, an attacker can precompute hashes for millions of common passwords and dictionary words, then compare those precomputed hashes against stolen password databases. These precomputed tables are called "rainbow tables." Adding a salt—a unique random string appended to each password before hashing—ensures that even identical passwords produce different hashes, making precomputed tables useless.
03Real-World Impact
If an attacker obtains a database of unsalted password hashes, they can match them against rainbow tables or run fast dictionary attacks to recover plaintext passwords in seconds or minutes. This leads to account takeover, unauthorized access to user data, and potential lateral movement within systems. The impact is especially severe because users often reuse passwords across multiple services, so a single compromised password database can expose accounts on other platforms.
Why it's vulnerable: The same password always produces the same hash. An attacker with the hash database can use precomputed rainbow tables to recover passwords in bulk.
<?php
function store_password($password) {
$hashed = sha1($password);
return $hashed;
}
function verify_password($password, $stored_hash) {
return sha1($password) === $stored_hash;
}
?>
Why it's vulnerable: Every instance of the same password produces an identical hash, enabling efficient dictionary and rainbow-table attacks.
Fixed pattern
<?php
function store_password($password) {
return password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
}
function verify_password($password, $stored_hash) {
return password_verify($password, $stored_hash);
}
?>
05Prevention Checklist
Use a modern password hashing algorithm that includes salt by default: bcrypt, scrypt, Argon2, or PBKDF2 with a high iteration count.
Never use fast hashing algorithms like MD5, SHA-1, or unsalted SHA-256 for passwords.
If you must implement salting manually, generate a cryptographically random salt of at least 16 bytes per password.
Audit existing password storage: if any hashes lack salt, force a password reset and rehash with salt on next login.
Use a key derivation function (KDF) designed for password hashing, not general-purpose cryptographic hashes.
06Signs You May Already Be Affected
Check your password storage code for calls to md5(), sha1(), sha256(), or similar functions applied directly to passwords without a salt parameter. If your database schema has a single "password_hash" column with no corresponding "salt" column, or if you see identical hashes for the same password across different user records, the system is likely using unsalted hashes. Review authentication logs for unusual login patterns or mass account compromise reports from users.