Performancemedium

Redact PII before sending logs to a telemetry backend

Implement a small client-side log scrubber that redacts PII (emails, tokens, credit cards) from log payloads before they leave the browser. Keep it fast and side-effect free.

Asked at CrowdStrike, Stripe

#security#logging#PII#telemetry

Answer

// Goals:
// - No mutation of caller objects (defensive copy).
// - Bounded depth and size to avoid pathological inputs.
// - Allowlist of obviously-safe keys, denylist of obviously-sensitive keys.

const SENSITIVE_KEYS = /(^|_)(password|token|secret|authorization|api[_-]?key|cookie|ssn)$/i

const PATTERNS = [
  // Emails
  { re: /[\w.+-]+@[\w-]+\.[\w.-]+/g, mask: '[email]' },
  // 13-19 digit card-ish numbers (with optional spaces/dashes)
  { re: /\b(?:\d[ -]*?){13,19}\b/g, mask: '[card]' },
  // JWT-shaped tokens
  { re: /\beyJ[\w-]+\.[\w-]+\.[\w-]+\b/g, mask: '[jwt]' },
  // Bearer / Basic header values
  { re: /\b(Bearer|Basic)\s+[A-Za-z0-9._\-+/=]+/g, mask: '$1 [redacted]' },
]

function redactString(str) {
  let out = str
  for (const { re, mask } of PATTERNS) out = out.replace(re, mask)
  return out
}

export function redact(value, depth = 0) {
  if (depth > 6) return '[depth-cut]'
  if (value == null) return value
  if (typeof value === 'string') return redactString(value)
  if (typeof value !== 'object') return value
  if (Array.isArray(value)) return value.map((v) => redact(v, depth + 1))

  const out = {}
  for (const [key, val] of Object.entries(value)) {
    if (SENSITIVE_KEYS.test(key)) {
      out[key] = '[redacted]'
      continue
    }
    out[key] = redact(val, depth + 1)
  }
  return out
}

// Usage
const event = {
  user: { email: 'alice@example.com', authorization: 'Bearer abc.def.ghi' },
  message: 'login failed for alice@example.com',
}
console.log(redact(event))
// { user: { email: '[email]', authorization: '[redacted]' },
//   message: 'login failed for [email]' }

// Follow-ups:
// - Move heavy regexes to a Web Worker if you redact at high volume.
// - Consider a JSON Schema-driven redactor when payload shape is known (faster).
// - Always redact on the client AND on the server; never trust either alone.

Practise more Performance questions →