CWE-532 (Insertion of Sensitive Information into Log File) is a direct path to credential theft: password hashes, session tokens, and API keys logged to stdout end up in your log aggregation platform, which typically has far weaker access controls than your primary database. PCI-DSS Req 10.3.3 explicitly prohibits logging cardholder data in any form; GDPR Art. 32 requires appropriate safeguards for personal data at rest and in transit — your log store is both. A single logger.info(req.body) in a payment handler can land card numbers, CVVs, and billing addresses in a third-party SaaS log platform, creating a compliance violation that persists for your entire log retention window. OWASP A09 lists sensitive data in logs as a primary logging failure mode.
Critical because logged secrets, tokens, or PII remain exploitable for the full log retention period and may be exfiltrated from log infrastructure, which is rarely as hardened as your primary data store.
Never log objects wholesale. Select only the fields you need, using explicit destructuring or field picks.
// WRONG — leaks everything in the user object including passwordHash
logger.info(user)
logger.debug(req.body)
// RIGHT — log only non-sensitive identifiers
logger.info({ userId: user.id }, 'User action')
logger.debug({ path: req.path, method: req.method }, 'Request received')
For Sentry, add a beforeSend scrubbing hook in your Sentry config file:
Sentry.init({
dsn: process.env.SENTRY_DSN,
beforeSend(event) {
if (event.request?.data) { delete event.request.data }
return event
}
})
After patching, run grep -r 'logger\.(info|debug|error)(user\|req\.body\|ctx)' app/ lib/ to confirm no wholesale object logging remains.
ID: saas-logging.app-logging.no-sensitive-data-logs
Severity: critical
What to look for: Enumerate all relevant files and Search server-side code for logging calls that include potentially sensitive fields. Look for patterns where user objects, request bodies, or context objects are logged wholesale (e.g., logger.info(req.body), console.log(user), logger.debug({ ...ctx })). Specifically check for logging of: passwords, password hashes, tokens (JWT, API keys, session tokens), credit card numbers or payment details, full email addresses in debug output, SSNs, health data, or any field named password, token, secret, key, ssn, credit_card, card_number, cvv. Also check Sentry/error reporter configuration for whether request data is sent unfiltered.
Pass criteria: No more than 0 violations are acceptable. No logging calls that pass raw request bodies, user objects, or other data structures that could contain sensitive fields without explicit field-level selection. Sensitive fields are either excluded from log output or scrubbed. If an error reporter (Sentry, etc.) is configured, it either excludes request body by default or has a beforeSend / denyUrls / data-scrubbing configuration. Report the count of conforming instances found even on pass.
Fail criteria: Any logging call found that passes a full user object, full request body, or any structure containing fields named password, token, secret, key, credit_card, ssn, or similar. OR an error reporter configured to send full request context without a scrubbing hook. A partial or incomplete implementation does not count as pass.
Skip (N/A) when: No server-side logging and no error reporting service configured.
Cross-reference: For API-level logging and monitoring patterns, the API Security audit covers request validation and error response handling.
Detail on fail: Describe specifically what was found and where. Do NOT include actual values from the code. Example: "logger.debug(user) in src/lib/auth.ts logs full user object including passwordHash field" or "Sentry initialized in lib/monitoring.ts with no beforeSend scrubbing — full request body sent on error"
Remediation: Logging sensitive data creates compliance violations (GDPR, HIPAA, PCI-DSS) and turns your log storage into an attack surface. A single breach of your logging infrastructure could expose all user credentials.
Never log objects wholesale. Always select specific fields:
// WRONG
logger.info(user)
logger.debug(req.body)
// RIGHT
logger.info({ userId: user.id, email: user.email }, 'User action')
logger.debug({ path: req.path, method: req.method }, 'Request received')
For Sentry, add a scrubbing hook:
Sentry.init({
dsn: process.env.SENTRY_DSN,
beforeSend(event) {
if (event.request?.data) {
delete event.request.data // or selectively redact fields
}
return event
}
})
After updating, search your codebase for any remaining console.log(user), logger.info(req.body), or similar patterns.