← Recipes

阅读中文版本

Redact PII in Application Logs

Add structured log redaction for emails, tokens, and card numbers so sensitive data never lands in log storage.

~30 minsecurityloggingprivacy

Task

Introduce a redaction layer that scrubs PII and secrets before logs are written.

When to use this

A support request exposes logs containing full email addresses and tokens, turning debugging data into a compliance problem.

Prerequisites

  • A structured logger with hooks
  • A list of sensitive field names
  • Log retention that includes central storage

Steps

1. Redact known sensitive keys recursively.

const SENSITIVE = /^(password|token|authorization|email|cardNumber|ssn)$/i;
function redact(obj) {
  if (Array.isArray(obj)) return obj.map(redact);
  if (obj && typeof obj === 'object') {
    return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, SENSITIVE.test(k) ? '[REDACTED]' : redact(v)]));
  }
  return obj;
}

Expected output: Sensitive keys are replaced with a marker before serialisation.

2. Add a test asserting secrets never appear.

test('no secrets in logs', () => {
  const line = JSON.stringify(redact({ user: 'a', token: 'super-secret' }));
  expect(line).not.toContain('super-secret');
});

Expected output: A regression test fails if a sensitive field is ever logged verbatim.

Troubleshooting

Problem

Secrets inside free-text messages

Solution

Avoid interpolating raw values into messages; log identifiers instead.

Problem

Redaction too narrow

Solution

Maintain the sensitive key list and test patterns against real log samples.

Limitations

  • Cannot catch PII embedded in unstructured text.
  • Over-redaction can hurt debugging.
  • Requires the logger to route through redaction.

What this recipe does

Introduce a redaction layer that scrubs PII and secrets before logs are written.

A support request exposes logs containing full email addresses and tokens, turning debugging data into a compliance problem.

Prerequisites

  • A structured logger with hooks
  • A list of sensitive field names
  • Log retention that includes central storage

Procedure

  1. Redact known sensitive keys recursively.
const SENSITIVE = /^(password|token|authorization|email|cardNumber|ssn)$/i;
function redact(obj) {
  if (Array.isArray(obj)) return obj.map(redact);
  if (obj && typeof obj === 'object') {
    return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, SENSITIVE.test(k) ? '[REDACTED]' : redact(v)]));
  }
  return obj;
}

Expected result: Sensitive keys are replaced with a marker before serialisation.

  1. Add a test asserting secrets never appear.
test('no secrets in logs', () => {
  const line = JSON.stringify(redact({ user: 'a', token: 'super-secret' }));
  expect(line).not.toContain('super-secret');
});

Expected result: A regression test fails if a sensitive field is ever logged verbatim.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows a test that logs a secret fails the redaction assert, and real logs contain markers instead of raw values.

Troubleshooting

Secrets inside free-text messages — Avoid interpolating raw values into messages; log identifiers instead.

Redaction too narrow — Maintain the sensitive key list and test patterns against real log samples.

Limitations

  • Cannot catch PII embedded in unstructured text.
  • Over-redaction can hurt debugging.
  • Requires the logger to route through redaction.