DEV Community

suhteevah
suhteevah

Posted on

Your Logs Are a Security Risk — 6 Patterns That Leak PII

Most teams treat logging as an afterthought. You add console.log during debugging, maybe upgrade to a structured logger eventually, and call it done. But here's the problem: logs are the largest unaudited data stream in most applications.

I spent months scanning codebases for logging anti-patterns. Here are the 6 most dangerous ones I keep finding.

1. Console.log With Full User Objects

The pattern:

app.post('/login', async (req, res) => {
  const user = await db.findUser(req.body.email);
  console.log('Login attempt:', user);
  // user object contains: email, hashedPassword, phone, address, tokens...
});
Enter fullscreen mode Exit fullscreen mode

Why it's dangerous: User objects contain emails, hashed passwords, tokens, phone numbers, addresses. All of it ends up in your log aggregator where every developer and ops engineer can see it.

The fix: Log only what you need — user ID, action, timestamp. Never log the full object.

2. Stack Traces With Sensitive Data

The pattern:

try {
  await processPayment(cardNumber, amount);
} catch(e) {
  logger.error(e.stack);
  // stack trace can contain function arguments including card details
}
Enter fullscreen mode Exit fullscreen mode

Why it's dangerous: Stack traces can contain function arguments, local variable values, database connection strings, and API keys from environment variable interpolation.

The fix: Sanitize stack traces before logging. Strip arguments, redact known sensitive patterns.

3. Missing Log Levels (Everything Is console.log)

When your entire codebase uses console.log for everything — errors, debug info, user actions, system events — you can't filter by severity, can't set up alerts on error-level events, and can't strip debug logs from production.

The fix: Pick a structured logger (winston, pino, bunyan). Use appropriate levels. Strip debug in production builds.

4. No Correlation IDs Across Services

When a request touches 5 microservices and something breaks, you have no way to trace the path if your logs don't share a correlation ID. Debugging production issues goes from minutes to hours.

The fix: Generate a correlation ID at the entry point, pass it through context, include it in every log line.

5. Mixed Logging Formats

Half the codebase uses winston with JSON output, the other half uses console.log with string interpolation. Your log aggregator can't parse inconsistent formats. Search and filtering break.

The fix: Pick one logger. Enforce it project-wide.

6. Silent Error Paths (Catch and Swallow)

try {
  const data = await db.query(sql);
} catch(e) {
  // TODO: handle this
  return [];
}
Enter fullscreen mode Exit fullscreen mode

The error happened but you'll never know. The function returns an empty array, something downstream breaks in a confusing way, and you have zero trail to follow.

The fix: Every catch block should log at minimum the error message, the function name, and relevant context.


Automate This

Logging is infrastructure. It deserves the same automated standards we apply to code style and test coverage. None of these patterns are hard to fix individually — the problem is that nobody checks.

I built LogSentry to scan for all 6 of these patterns (and 84 more) in one command:

clawhub install logsentry
logsentry scan .
Enter fullscreen mode Exit fullscreen mode

Free to scan. Pro ($19/mo) adds pre-commit hooks so these patterns can't merge. Runs 100% locally — your log analysis never leaves your machine.

What logging anti-patterns have you run into? I'd love to hear what I'm missing.

Top comments (0)