Server-side console.log(req.body), logger.info({ user, session }), or Sentry.captureException(err, { extra: { headers } }) calls that dump full request bodies, card numbers, CVVs, session tokens, or API keys have two compounding cost consequences beyond privacy exposure. First, PCI scope expansion — the moment a credit-card field lands in a log line, the log ingestion pipeline (Datadog, CloudWatch, Loki, Sentry, Logtail) becomes "in-scope" for PCI-DSS audits, adding roughly $50K-$200K per year in compliance overhead for QSA assessments, retention encryption, and access-control review. Second, abuse-replay blast radius — anyone with log read access (your ops team, Sentry seat-holders, a compromised vendor) can replay sessions, hijack tokens, or reuse cards. The 2022 Twilio incident exposed years of customer PII because log infrastructure was compromised; Capital One's 2019 IAM-misconfigured S3 logs resulted in 100M records leaked. PCI-DSS Req 3.2 explicitly prohibits storing authentication data post-authorization in any unprotected location, including logs. AI scaffolding produces this pattern casually: "add logging" becomes console.log(req.body) without a redactor in the loop.
High because one tainted log pipeline can expand PCI scope by hundreds of thousands of dollars per year and any log reader effectively becomes an auth principal.
Strip sensitive fields before logging: introduce a redact(obj) helper that drops password, token, apiKey, cardNumber, cvv, authorization, cookie, session, and full req.body / req.headers objects, and route every console.log or logger.* call through it. For Sentry, configure beforeSend to scrub the same fields. Log scope markers ([auth-flow] step 2 userId=abc123) instead of full objects.
Deeper remediation guidance and cross-reference coverage for this check lives in the security-hardening and saas-logging Pro audits — run those after applying this fix for a more exhaustive pass on the same topic.
project-snapshot.abuse.no-pii-in-server-logshighapp/api/**, pages/api/**, server components, lib/**, server/**, middleware files) for console.log, console.error, console.warn, console.debug, logger.info, logger.debug, logger.error, logger.warn, and Sentry.captureException(..., { extra: ... }) calls whose argument list includes any of: req.body, req.headers, cookies(), headers(), user (full object), session, email, password, pinHash, token, apiKey, api_key, cardNumber, card_number, cvv, expiryDate, ssn, phone, address, firstName, lastName. Also flag whole-request dumps: console.log(req), console.log(JSON.stringify(req.body)), logger.info(event) where event is the raw handler input. Scope markers like console.log('[auth-flow] step 2') or logger.info({ userId }) (opaque id only, no PII) are fine.app/api, pages/api, and server/ directories as evidence.req.body "for debugging" — it still ships to production log infrastructure."0 sensitive-log matches across N server-side files scanned"."Scanned ~X server-side files, 0 sensitive-field log patterns matched"."Full request body logged in app/api/auth/login/route.ts — console.log(req.body) includes password field" — name the file, the log call, and the specific sensitive field being dumped.redact(obj) helper that drops password, token, apiKey, cardNumber, cvv, authorization, cookie, session, and full req.body / req.headers objects, and route every console.log or logger.* call through it. For Sentry, configure beforeSend to scrub the same fields. Log scope markers ([auth-flow] step 2 userId=abc123) instead of full objects.