VNX-836: Use of Password Hash Instead of Password for Authentication
Detects pass-the-hash authentication: a stored password hash compared directly with a value from the request, without hashing a password on the server. Python, Java and JavaScript/TypeScript.
| Field | Value |
|---|---|
| Rule ID | VNX-836 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, JavaScript / TypeScript, Python |
| CWE | CWE-836 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | password-hash-auth pass-the-hash authentication cwe-836 |
| Source | internal/sast/rules/vnx-836.rego |
Overview
VNX-836 maps to CWE-836: Use of Password Hash Instead of Password for Authentication. When a login endpoint accepts a hash from the client and compares it with the stored hash, the hash is the password. Anyone who reads the user table (a SQL injection, a leaked backup) can log in as every user without cracking anything.
The rule reports a comparison (==, !=, ===, .equals(), compare_digest(), MessageDigest.isEqual(), crypto.timingSafeEqual()) between a stored-hash field or getter (password_hash, passwordHash, hashed_password, pwd_hash, getPasswordHash()) and a request value: request.form/args/json/POST/GET, request.getParameter/getHeader, req.body/query/params/headers, a variable assigned from one within the ten lines above, or a Spring @RequestParam/@RequestHeader String parameter.
What Gets Flagged
if user is None or user.password_hash != request.form["password_hash"]: # FLAGGED
abort(401)
if (!user || user.passwordHash !== req.body.passwordHash) { // FLAGGED
return res.status(401).end();
}
if (user.getPasswordHash().equals(request.getParameter("hash"))) { // FLAGGED
What Is Not Flagged
- The request password hashed on the server before the comparison (
hashlib,pbkdf2_hmac,bcrypt,hash_password()and similar). bcrypt.compare(req.body.password, user.passwordHash),check_password_hash(...)and other verify functions.- Comparisons of two stored hashes, and the pattern in comments or string literals.
Remediation
Accept the password itself over TLS and verify it on the server with a password hashing function (bcrypt, scrypt, Argon2, PBKDF2) and its verify call. If the client must not send the password, use a challenge-response or token protocol rather than a static hash.
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-836
// nosec vnx-836
Or record an ignore rule: vulnetix ignore add --rule vnx-836 --reason "...". See Suppressing findings.