VNX-359: Private personal information written to logs or standard output
Reports logging and print calls in Python, JavaScript/TypeScript and Java whose arguments name a social security number, passport number, date of birth, national ID, tax ID, driver's licence or medical record number.
| Field | Value |
|---|---|
| Rule ID | VNX-359 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Java, JavaScript / TypeScript, Python |
| CWE | CWE-359 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | pii-exposure logging privacy cwe-359 |
| Source | internal/sast/rules/vnx-359.rego |
Overview
VNX-359 maps to CWE-359: Exposure of Private Personal Information to an Unauthorized Actor. It reports a value that identifies a person passed to a logging call or printed:
- Python:
logging/logger/log/app.loggercalls andprint. - JavaScript/TypeScript:
console.*, andlogger/log/winston/pino/bunyan/req.logcalls. - Java:
log/logger/LOG/LOGGERcalls andSystem.out/System.errprint methods.
A call is reported when its arguments, followed across up to four continuation lines and including f-string and template-literal interpolations, name a social security number, passport number, date of birth, national ID or national insurance number, tax ID, driver’s licence number or medical record number as an identifier, property, getter or object key (applicant.ssn, customer.getSsn(), dateOfBirth, passport_number, { ssn }).
Not reported: the words inside a string literal ("Collecting SSN"), lookalike names (has_passport, dobVerified, ssnMasked), arguments that are masked, redacted, hashed, truncated to the last four or reduced to a null/presence check (each argument is judged on its own, so a hashed argument does not excuse a raw one beside it), comments, and test files. Credentials and card numbers in logs are VNX-NODE-031 and VNX-GO-040.
Why This Matters
Logs are copied to log shippers, search clusters, support tools and backups, and they are read by many people who have no business seeing a customer’s identity documents. A logged SSN or passport number is a reportable personal-data exposure under most privacy laws, and it outlives the record it came from.
What Gets Flagged
# FLAGGED
logger.info("registering applicant %s ssn=%s", applicant.name, applicant.ssn)
logging.debug(f"passport {applicant.passport_number} dob {applicant.date_of_birth}")
// FLAGGED
log.info("Onboarding {} with SSN {}", customer.getName(), customer.getSsn());
System.out.println("DOB: " + customer.getDateOfBirth());
# NOT FLAGGED
logger.info("ssn on file: %s", mask(applicant.ssn))
logger.info("Collecting SSN and date of birth for applicant %s", applicant.id)
Remediation
- Log a record identifier, not the personal data itself.
- Where a value must appear, mask it (last four digits at most) through one shared helper.
- Add a log filter or structured-logging redaction for known PII field names as a backstop.
References
- CWE-359: Exposure of Private Personal Information to an Unauthorized Actor
- OWASP Logging Cheat Sheet: Data to exclude
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-359
// nosec vnx-359
Or record an ignore rule: vulnetix ignore add --rule vnx-359 --reason "...". See Suppressing findings.