Mesrai
Back to blog
// essayTechnical Deep Dive

The Logging Statement That Was Quietly Writing PII to Datadog

Real incident: log statement printing req.body sent PII to Datadog for 6 months. SOC2 audit finding. Redaction fix.

Mesrai TeamSeptember 4, 20268 min read

Real incident: a debug log statement printed the entire request body to logs. For months, every signup, profile update, and payment-method-add wrote email, phone, address, and last-4 of card to Datadog. Discovered during a SOC2 audit. Mesrai catches the shape on every PR.

The vulnerable diff

tslib/log-middleware.ts
// lib/log-middleware.ts (the buggy middleware)
export function requestLogger(req, res, next) {
  // BUG: req.body contains PII on user-facing endpoints
  log.info({ method: req.method, path: req.path, body: req.body }, "request received");
  next();
}

// During incident investigation:
// Datadog Logs query: `service:api source:nodejs` →
//   3.2M log entries with raw PII (email, phone, address, card.last4)
//   over the past 6 months.

What is wrong

Observability platforms (Datadog, Splunk, ELK) are designed for fast search and retention — they are NOT designed as a PII store. Sending raw user PII into logs has several problems: log retention typically exceeds your data retention policy; the platform's access controls may be broader than your DB's; logs are often shipped to multiple regions; logs are common targets in supply-chain attacks. The fix is to redact at log time — strip sensitive keys from request bodies before logging, or omit body logging entirely on user-facing endpoints.

The attack

Audit finding:

textexploit
During SOC2 readiness assessment:
- Auditor queries Datadog logs for "email" field.
- 3.2M entries. PII present in plain text.
- Audit finding: control failure on data minimization (CC6.7).
- Remediation: redaction policy + log retention reduction + incident
  notification to affected users.
- Cost: ~$80K in remediation + audit re-test fees.

Catastrophic.

Mesrai's review comment

textreview-comment.txt
mesraipilot · Bot · reviewed 1 min ago

[mesrai] [code-review] [Security] [PII-Leak] [critical]

Logging `req.body` writes user PII to your log aggregator. This is
a compliance failure (GDPR Art. 5.1.c data minimization, SOC2 CC6.7,
DPDP Act § 8) and an exposure risk.

Two-layer fix:

  1. Don't log raw bodies on user-facing endpoints:

     log.info({
       method: req.method,
       path: req.path,
       userId: req.user?.id,
       statusCode: res.statusCode,
     }, "request");

  2. Add a serializer that redacts sensitive keys for any body
     logging you do want:

     // pino example
     const SENSITIVE = ["password","token","authorization","email",
                        "phone","ssn","aadhaar","card","cvv","accountNumber"];

     const logger = pino({
       redact: { paths: SENSITIVE, censor: "[REDACTED]" },
     });

For existing log entries: bulk-delete in Datadog via the API,
shorten retention to 7 days going forward, and notify affected
users if your DPA requires it.

The fix

tslib/log-middleware.ts + lib/logger.ts (fixed)
// lib/log-middleware.ts — fixed
export function requestLogger(req, res, next) {
  log.info({
    method: req.method,
    path: req.path,
    userId: req.user?.id,
  }, "request");
  res.on("finish", () => {
    log.info({
      method: req.method, path: req.path, status: res.statusCode,
      durationMs: Date.now() - req.startTime,
    }, "response");
  });
  next();
}

// lib/logger.ts (the redacting logger if used elsewhere)
import pino from "pino";
const SENSITIVE = [
  "password","token","authorization","email","phone","ssn","aadhaar",
  "card.number","card.cvv","cvv","accountNumber","ifsc",
  "*.password","*.email","*.phone",  // wildcards for nested
];
export const log = pino({ redact: { paths: SENSITIVE, censor: "[REDACTED]" } });

Minimal request log: method, path, userId only. Response log adds status + duration. Logger has a redaction policy so any incidental body logging strips sensitive fields. PII never reaches Datadog.

Why human review missed it

PII-in-logs is one of the most common SOC2/GDPR audit findings. Mesrai catches every log statement that prints `req.body`, `req.query`, or other potentially-PII fields without redaction.

Related rules + further reading

Mesrai rule pack: security/no-pii-in-logs — flags log statements with req.body, req.query, password, email, token, etc.

OWASP Logging Cheat Sheet: PII handling.

GDPR Art. 5.1.c — data minimization. DPDP § 8.

Takeaway

Logs are not a PII store. Redact at log time. Audit your existing logs. Mesrai catches the pattern at PR time.

// try

See it on your next PR.

Free for individuals. Install in two minutes. Mesrai reviews every commit.