Weak Password Hashing (MD5/SHA1)
What Is This Vulnerability?
Weak password hashing means storing user passwords using fast, non-salted hash functions like MD5 or SHA1 instead of purpose-built password hashing algorithms. These fast algorithms can be brute-forced at billions of attempts per second on modern GPUs, allowing attackers who obtain the hash database to recover most passwords quickly.
Why It Happens
Developers may use MD5 or SHA1 out of familiarity, not understanding the difference between cryptographic hashing and password hashing. Legacy codebases often predate modern password hashing libraries. Some developers mistakenly believe adding a salt to MD5 makes it secure, when the fundamental problem is the hash function's speed.
Example Code
import crypto from "crypto";
async function registerUser(username: string, password: string) {
const hash = crypto.createHash("md5").update(password).digest("hex");
await db.query(
"INSERT INTO users (username, password_hash) VALUES ($1, $2)",
[username, hash]
);
}
async function verifyUser(username: string, password: string) {
const hash = crypto.createHash("md5").update(password).digest("hex");
const result = await db.query(
"SELECT * FROM users WHERE username = $1 AND password_hash = $2",
[username, hash]
);
return result.rows[0] ?? null;
}import bcrypt from "bcrypt";
const SALT_ROUNDS = 12;
async function registerUser(username: string, password: string) {
const hash = await bcrypt.hash(password, SALT_ROUNDS);
await db.query(
"INSERT INTO users (username, password_hash) VALUES ($1, $2)",
[username, hash]
);
}
async function verifyUser(username: string, password: string) {
const result = await db.query(
"SELECT * FROM users WHERE username = $1",
[username]
);
const user = result.rows[0];
if (!user) return null;
const match = await bcrypt.compare(password, user.password_hash);
return match ? user : null;
}How Hackers Exploit It
After obtaining a database dump (through SQL injection, a backup leak, or a compromised admin panel), attackers run the hashes through precomputed rainbow tables or GPU-accelerated cracking tools like Hashcat. MD5 hashes can be cracked at over 60 billion attempts per second on a modern GPU. Most common passwords are recovered within seconds to minutes.
How to Fix It
Use bcrypt, scrypt, or Argon2 for password hashing. These algorithms are intentionally slow and include built-in salting, making brute-force attacks computationally expensive. Set the work factor high enough that hashing takes at least 100ms per password. Migrate existing MD5/SHA1 hashes by re-hashing passwords on the next successful login.