VNX-261: Weak Encoding for Password
A password is passed straight to base64, hex or ROT13 encoding, which anyone who reads the stored or logged value can reverse.
| Field | Value |
|---|---|
| Rule ID | VNX-261 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Go, Java, JavaScript / TypeScript, PHP, Python, Ruby |
| CWE | CWE-261 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | crypto encoding cwe-261 |
| Source | internal/sast/rules/vnx-261.rego |
Overview
VNX-261 maps to CWE-261: Weak Encoding for Password. It reports a call to a reversible encoder (base64, hex, ROT13) whose argument is a password: an identifier ending in password, passwd, pwd or passphrase, a password field of a request, or a variable assigned from one in the six lines above.
Why This Matters
Encoding is not protection. A base64, hex or ROT13 “password” in a database, a configuration file, a cookie or a log line is the password, one function call away. Anyone who can read the column, the backup or the log can sign in as the user, and often on other sites where the same password was reused.
What Gets Flagged
stored = base64.b64encode(request.form["password"].encode("utf-8"))
cfg["backup"] = codecs.encode(backup_password, "rot13")
const encoded = Buffer.from(req.body.password).toString('base64');
localStorage.setItem('pw', btoa(form.userPassword));
String encoded = Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8));
user.setPassword(DatatypeConverter.printBase64Binary(req.getNewPassword().getBytes()));
u.Password = hex.EncodeToString([]byte(pwd))
$stored = base64_encode($_POST['password']);
return str_rot13($password);
self.encoded_password = Base64.strict_encode64(new_password)
Not flagged: HTTP Basic credentials (base64(user + ":" + password), or a line building an Authorization/Basic header), which the protocol requires; a password that is hashed, derived, signed or encrypted before encoding (b64encode(hashlib.sha256(pw).digest()), encodeToString(md.digest(...)), encodeToString(cipher.doFinal(...))); decoding; lookalike names such as passwordHash or password_reset_token; and the calls written in comments or string literals.
Remediation
- To verify a password, store a salted, slow hash: bcrypt, scrypt, Argon2id or PBKDF2 with a high iteration count.
- If the application must recover the password (for example to log in to another system), encrypt it with a key held in a secrets manager or KMS, not with an encoding.
- Never log a password, encoded or not.
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-261
// nosec vnx-261
Or record an ignore rule: vulnetix ignore add --rule vnx-261 --reason "...". See Suppressing findings.