Skip to content
Security First — Part 24 of 30

What to Log and What NEVER to Log

Written by claude-sonnet-4 · Edited by claude-sonnet-4
loggingsecuritypiigdprobservabilitytypescript

The $101 Million Lesson Nobody Talks About

In 2019, Meta's engineers were doing a routine security review when they found something alarming: hundreds of millions of Facebook and Instagram passwords sitting in internal log files -- in plain text. Not hashed. Not masked. Just sitting there, readable, accessible to roughly 20,000 employees.

Five years later, Ireland's Data Protection Commission handed Meta a EUR 91 million ($101 million) fine. The violation? Storing those passwords in logs without adequate security measures, and failing to report the breach to regulators within GDPR's required 72-hour window. (PCMag, September 2024)

The kicker: it was almost certainly not intentional. Some middleware layer, some logging configuration, some line of code -- probably auto-generated or copy-pasted -- that said "log the whole request body." And suddenly, passwords were flowing into log files for years.

Twitter had a nearly identical incident in 2018. Passwords were written to an internal log before the hashing step completed. (ZDNET, 2018) GitHub had the same thing happen the same week.

These are not small startups run by careless developers. They are some of the most sophisticated engineering organizations on Earth. And yet: the logs ate the secrets.

If it can happen to them, it can absolutely happen to your app.


Why Logging Matters -- And Why It Can Hurt You

Logs are the nervous system of your application. When something breaks at 2am, logs tell you what happened. When a user says "I never did that," logs tell you what actually occurred. When you need to debug a mysterious error, logs are your only witness.

But logs are also a liability. Every log line is a record that:

  • Gets written to disk, often unencrypted
  • Gets forwarded to a third-party log aggregator (Datadog, Logtail, Axiom, Papertrail)
  • Gets retained for 30, 60, sometimes 365 days
  • Can be read by anyone with access to your logging platform
  • May be subpoenaed, audited, or breached

The moment personal data enters a log file, it becomes subject to GDPR in Europe and CCPA in California. That is not a hypothetical. In 2025, EU regulators issued over EUR 1.2 billion in GDPR fines, with personal data breach reports rising 22% year-over-year. (TechRadar / Yahoo Finance, January 2026)


What You SHOULD Log

Good logs answer operational questions without exposing user data. Stick to this list:

  • Timestamps -- when did this happen?
  • HTTP method and path -- GET /api/products/123
  • HTTP status code -- 200, 404, 500
  • Response duration -- 142ms
  • User ID (an internal identifier, never an email) -- user_id: u_8f2a3c
  • Event names -- payment.initiated, login.success, export.requested
  • Error type and message -- TypeError: Cannot read property 'id' of undefined
  • Request ID -- a unique identifier to trace a request through your system
  • Environment and service name -- production, api-gateway

None of this tells an attacker anything useful. All of it tells you everything you need to debug problems and monitor your system.


What You Must NEVER Log

Here is the list. Print it out and tape it to your monitor.

  • Passwords (in any form -- hashed or plaintext)
  • API keys and secret tokens
  • JWT tokens or session tokens
  • Full credit card numbers (even partial -- only last 4 digits are acceptable, per PCI DSS)
  • Social Security Numbers or national ID numbers
  • Email addresses (they are PII under GDPR and CCPA)
  • Full request bodies (they may contain any of the above)
  • Authorization headers (Authorization: Bearer eyJhb...)
  • Personally Identifiable Information: full names, addresses, phone numbers, dates of birth

If you log any of these, you have created a compliance liability the moment the log is written -- regardless of whether anyone ever reads it.


The AI Code Problem

Here is something that should concern every vibe coder: AI-generated code has a logging problem.

Veracode's 2025 GenAI Code Security Report found that AI models generate insecure log injection code 88% of the time. (Veracode, September 2025) Apiiro's research found a 40% increase in secrets exposure in AI-assisted codebases. When you ask an AI to "add logging so I can debug this," it frequently logs the entire request object -- which includes headers, body, query params, and anything else that came through.

When you ask an AI to "add error handling with logging," it may log error.message along with whatever context it was passed -- potentially including user data.

This is not the AI being malicious. It is the AI being helpful in a way that does not understand threat models. The AI was trained on millions of public repositories, many of which have bad logging practices. It reproduces those patterns faithfully.

The fix is simple: audit the logging in any AI-generated code before you ship it.


Log Sanitization: A Practical TypeScript Example

The right approach is a logger wrapper that strips sensitive fields before anything gets written. Here is a pattern you can use today:

// logger.ts
import pino from "pino";

const REDACTED_KEYS = [
  "password",
  "passwd",
  "secret",
  "token",
  "apiKey",
  "api_key",
  "authorization",
  "credit_card",
  "creditCard",
  "cardNumber",
  "ssn",
  "email",
  "phone",
  "address",
];

function redact(obj: Record<string, unknown>): Record<string, unknown> {
  if (!obj || typeof obj !== "object") return obj;
  return Object.fromEntries(
    Object.entries(obj).map(([k, v]) => {
      if (REDACTED_KEYS.some((key) => k.toLowerCase().includes(key))) {
        return [k, "[REDACTED]"];
      }
      if (typeof v === "object" && v !== null) {
        return [k, redact(v as Record<string, unknown>)];
      }
      return [k, v];
    })
  );
}

const base = pino({ level: process.env.LOG_LEVEL || "info" });

export const logger = {
  info: (msg: string, data?: Record<string, unknown>) =>
    base.info(data ? redact(data) : {}, msg),
  error: (msg: string, data?: Record<string, unknown>) =>
    base.error(data ? redact(data) : {}, msg),
  warn: (msg: string, data?: Record<string, unknown>) =>
    base.warn(data ? redact(data) : {}, msg),
};

Now instead of:

// BAD -- AI-generated, logs everything
console.log("Incoming request", req.body);

You write:

// GOOD -- logs only what matters
logger.info("Incoming request", {
  method: req.method,
  path: req.path,
  userId: req.user?.id,
  duration: Date.now() - startTime,
  status: res.statusCode,
});

The wrapper will also catch anything that accidentally slips through -- if a future developer adds email to that log object, [REDACTED] will appear in the log instead.


Where Logs Go

Many vibe coders think logs just appear in the terminal. In production, they travel much further:

  • Console / stdout -- fine for local development, nothing in production
  • Structured logging libraries (Pino, Winston) -- write JSON logs to stdout that other tools consume
  • Log aggregators (Datadog, Logtail, Axiom, Papertrail) -- collect, store, and index your logs for search and alerting

The moment logs leave your server and go to a third-party aggregator, they are subject to that vendor's data processing terms. Logging user email addresses to Datadog means Datadog is processing PII -- and you need a Data Processing Agreement in place, or you have a GDPR violation.

Check your aggregator's data region settings. If you serve EU users, logs containing any PII must stay within the EU under GDPR's data transfer rules.


Retention and Access Control

Log retention is a silent risk. Logs that you never look at are still a liability if they contain sensitive data.

Set retention policies intentionally:

  • Application logs: 30 days is usually sufficient
  • Security/audit logs: 90-365 days, depending on your compliance requirements
  • Logs containing any PII: subject to GDPR's data minimization principle -- only retain as long as necessary, and document why

On access control: in most startups, every developer can read production logs. That may be fine today. But if your logs contain user IDs, IP addresses, or behavioral data, you have created a system that knows a great deal about your users -- and anyone with log access knows it too.

Limit log access to people who need it. Log access itself should be logged.


Quick Audit: Grep Your Codebase Right Now

Open a terminal in your project and run these commands. If any of them return results, you have work to do:

# Look for full request body logging
grep -r "req\.body" --include="*.ts" --include="*.js" .

# Look for console.log with potentially sensitive objects
grep -r "console\.log.*req\|console\.log.*user\|console\.log.*body" --include="*.ts" --include="*.js" .

# Look for logged authorization headers
grep -r "authorization\|Authorization" --include="*.ts" --include="*.js" . | grep -i "log\|print\|console"

# Look for password appearing in log statements
grep -ri "password" --include="*.ts" --include="*.js" . | grep -i "log\|console\|print"

# Look for email being logged
grep -ri "\.email" --include="*.ts" --include="*.js" . | grep -i "log\|console\|print"

This takes five minutes. It has saved teams from serious breaches and six-figure fines.


Checklist: Secure Logging for Vibe Coders

  • Replace all console.log calls with a structured logger (Pino or Winston)
  • Add a redaction wrapper that strips sensitive fields before logging
  • Never log req.body directly -- select only the fields you need
  • Never log authorization headers, tokens, or API keys
  • Never log passwords, SSNs, full card numbers, or email addresses
  • Use internal user IDs in logs, not emails
  • Run the grep audit above on your codebase
  • Set log retention policies in your aggregator (30 days for most app logs)
  • Restrict log access to people who genuinely need it
  • If you serve EU users, confirm your log aggregator stores data within the EU or has a valid transfer mechanism
  • Review any AI-generated logging code before deploying -- assume it logs too much

Ask The Guild

Take five minutes right now and run the grep audit on your project. What did you find?

Share in the comments: Did you find any unexpected logging of sensitive data? Was it in your own code, or in AI-generated code? What did you do to fix it?

The best security communities learn from each other's near-misses. Your story might save someone else from a very expensive lesson.

Copy A Prompt Next

Start safely

If this article changed how you think about the problem, copy a prompt that turns that judgment into one safe, reviewable next step.

Matching public prompts

6

Keep the task scoped, copy the prompt, then inspect one reviewable diff before the agent continues.

Need the safest first move instead? Open the curated sample prompts before you browse the broader library.

Start Here — Build Safely With AIStart Here — Build Safely With AI

Choose a Tiny First Win

How to pick a first project that teaches the workflow without dragging you into complex product and engineering problems.

Preview
"I need help shrinking this idea into a safe first vibe-coded project.
The big idea is: [describe idea]
Reduce it to the smallest useful version by:
1. removing anything that requires auth, billing, production data, or complicated integrations
2. keeping only one user and one core job to be done
Security First

Turn this security lesson into a repeatable review habit

This article gives you the judgment call. The security paths give you the vocabulary, checklists, and repetition to catch the next issue before it reaches users.

Best Next Path

Compliance and Professional Security

Guild Member · $29/mo

Translate security advice into PCI, HIPAA, SOC 2, and real audit-facing controls instead of hand-wavy best practices.

15 lessonsIncluded with the full Guild Member library

Need the free route first?

Start with Start Here — Build Safely With AI if you want the workflow and vocabulary before you dive into the deeper path above.

T

About Tom Hundley

Tom Hundley writes for builders who need stronger technical judgment around AI-assisted software work. The Guild turns production experience into public articles, copy-paste prompts, and structured learning paths that help non-software developers supervise AI agents more safely.

Do this next

Leave this article with one concrete move. Copy the matching prompt, or start with the path that teaches the safest next skill in sequence.