Password storage: hash with bcrypt, scrypt or Argon2

A database of plaintext passwords is a list of logins to other sites, because people reuse passwords. Whoever reads the table — through a backup, an injection or an insider — gets all of them.

Example

Vulnerable
this.addUser = (userName, password, callback) => {
  users.insertOne({ userName, password }, callback);
};
Fixed
const bcrypt = require("bcrypt");

this.addUser = async (userName, password) => {
  const hash = await bcrypt.hash(password, 12);
  return users.insertOne({ userName, password: hash });
};
// at login: await bcrypt.compare(attempt, user.password)

How it goes wrong

Passwords written straight to the users table are the obvious case. Fast hashes are the subtle one: MD5, SHA-1 and plain SHA-256 can be computed billions of times per second on a GPU, so a leaked table of them is cracked in days. Unsalted hashes also let one precomputed table cover every user.

How to fix it

Use a slow, salted password hash and the library's verify function.

  • bcrypt (cost 12 or more), scrypt or Argon2id
  • Verify with the library's constant-time compare, never by comparing strings
  • Rehash on login when you raise the cost
  • Rate-limit login attempts and do not reveal whether the username exists

How RepoVerse finds it

  • HighPassword stored without hashing

    Anyone who reads the database — a backup, an injection, an insider — gets every user's password, and with it their accounts on other sites.

    data flow · CWE-256

  • ModeratePassword or token hashed with a broken digest

    MD5 and SHA-1 are fast and collision-prone, which is exactly wrong for a secret — a commodity GPU walks a stolen table of them.

    pattern

Questions

Is SHA-256 with a salt good enough for passwords?
No. Salting stops precomputed tables, but SHA-256 is designed to be fast, which is what an attacker cracking passwords wants. Password hashes are deliberately slow and tunable.
How does RepoVerse detect plaintext passwords?
It looks for password fields written to a database through insert, save or create calls with no hashing call anywhere near them and no pre-save hashing hook in the model.

Related

Updated 2026-10-11