VNX-210: Self-generated Error Message Containing Sensitive Information
Detects errors the program raises itself whose message carries a secret value (password, secret, API key, private key, token, credential, DSN, connection string): Go fmt.Errorf/errors.New/http.Error/panic, Python raise/abort/HTTPException, Java throw new/sendError, JavaScript new Error/createError/res.status(4xx|5xx).
| Field | Value |
|---|---|
| Rule ID | VNX-210 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | Go, Java, JavaScript / TypeScript, Python |
| CWE | CWE-210 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | error-handling self-generated information-exposure cwe-210 |
| Source | internal/sast/rules/vnx-210.rego |
Overview
VNX-210 maps to CWE-210: Self-generated Error Message Containing Sensitive Information. When code detects a failure and writes its own error message, it is easy to include the very value that failed: the rejected API key, the password that did not match, the DSN that would not connect. That message then travels to the client, to logs, to crash reporters and to monitoring, and the secret travels with it.
The rule reports an error construction whose message includes a secret’s value, outside any string literal: an argument, a concatenation, a %/.format()/String.format argument, or an f-string or template-literal interpolation. A value counts when its name ends in password, passwd, passphrase, pwd, secret, apiKey/api_key, privateKey, token, credential(s), dsn or connection string (cfg.Password, client_secret, refreshToken, tokenString, config.getPassword()).
| Language | Error constructions |
|---|---|
| Go | fmt.Errorf, errors.New/Errorf/Wrap/Wrapf, status.Errorf, http.Error, panic, gin c.JSON/String/AbortWithStatusJSON with a 4xx/5xx status |
| Python | raise X(...), abort(...), HTTPException(...) |
| Java | throw new X(...), response.sendError(...), new ResponseStatusException(...) |
| JavaScript, TypeScript | new Error(...) and every ...Error(...), createError(...), `res.status(4xx |
What Gets Flagged
return fmt.Errorf("connect %s as %s/%s: %w", cfg.Host, cfg.User, cfg.Password, err) // FLAGGED
return errors.New("api key rejected: " + apiKey) // FLAGGED
raise PermissionError(f"unknown api key {api_key}") # FLAGGED
throw new Error(`No session for token ${sessionToken}`); // FLAGGED
What Is Not Flagged
- The secret’s name only in the message text:
throw new Error('password is required'). - Metadata about a secret:
password.length,len(password),secret.Name,tokenType,secretName,passwordLen. - Sentinel errors such as
ErrInvalidToken, and values passed through a non-getter call (hash(password)). - A condition on the secret rather than its value:
password ? 'rejected' : 'missing',tokenProvided: !!token. - Object keys (
{ tmpToken: ... }), logging calls (covered by VNX-SEC-022 and the per-language logging rules), and test code.
Remediation
Say what failed, not what the value was.
return fmt.Errorf("connect %s as %s: %w", cfg.Host, cfg.User, err)
References
- CWE-210: Self-generated Error Message Containing Sensitive Information
- OWASP: Improper Error Handling
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-210
// nosec vnx-210
Or record an ignore rule: vulnetix ignore add --rule vnx-210 --reason "...". See Suppressing findings.