Password column stored in plain text
- Rule:
schema-plaintext-password-column - Default severity: High
- CWE: CWE-256 (Plaintext Storage of a Password)
- Risk category: Data protection
A login password column is written with the raw value. If the database leaks, every account's password is readable as-is, and users who reuse passwords are exposed on other sites too.
What Vulkro detects
Vulkro finds the password column in the database schema (a model or a migration), then every place the code assigns it inside a create, update or save call. The rule fires when none of those write sites hashes the value: not the write itself, not the value's own assignment, and not the model's own file through a pre-save hook or a setter. Test, seed, fixture and mock files are not counted as write sites.
The finding is anchored at the write site, and its message names the line where the column is declared.
Remediation. Hash the password with a slow, salted password hash before
it is stored: bcrypt (cost 12 or more), argon2id or scrypt. Do it in one
place the model owns (a pre('save') hook, a setter, set_password,
Hash::make, a PasswordEncoder) so no write path can skip it, and compare
with the library's constant-time verify function on login. Then force a
reset for any account whose stored value is not a hash.
Non-compliant code (example)
// models/user.js
const userSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
// controllers/auth.js: the password from the request body is stored as-is.
exports.register = async (req, res) => {
const user = await User.create({
email: req.body.email,
password: req.body.password,
});
res.status(201).json({ id: user.id });
};
Compliant code (example)
// controllers/auth.js: the password is hashed with bcrypt before it is stored.
exports.register = async (req, res) => {
const passwordHash = await bcrypt.hash(req.body.password, 12);
const user = await User.create({
email: req.body.email,
password: passwordHash,
});
res.status(201).json({ id: user.id });
};