Your logs are leaking secrets in 24 languages
Every leaked credential has the same origin story. Nobody commits password = "hunter2" to GitHub anymore — scanners catch that. What actually happens is quieter: someone writes
logger.info({ user }, 'login ok');
and user happens to carry a session token. The code review looked fine. The log aggregator, the error tracker, and three SaaS vendors now have a copy — forever.
## Field names are the wrong abstraction
The standard fix is a redaction path list: tell pino to hide req.headers.authorization, user.password, and so on. It works until:
- the secret is in a field called
note, because a support agent pasted an AWS key into a ticket; - your app logs text in Turkish, and the field is called
şifrə, notpassword; - the token is inside a stack trace, not a field at all.
A blocklist of names can't see content. So I built flare-redact to read the values themselves.
## Rule 1: if you can't validate it, don't flag it
Content scanning has a reputation problem: false positives. Nobody keeps a tool that redacts random order IDs.
The fix is checksums. A 16-digit number is only a "credit card" if it passes Luhn. An IBAN has a mod-97 check. National IDs are stricter: India's Aadhaar uses the Verhoeff algorithm, France's NIR carries
official documentation examples.
Token formats do the same job for secrets: sk-ant-…, ghp_…, hvs.…, whsec_… are distinctive enough that false positives are effectively zero. Version 1.1.0 ships 75 detectors.
## Rule 2: hostile input is the normal case
A redactor runs on attacker-influenced text by definition — that's the whole point. Two consequences:
- ReDoS is a real threat. Every pattern uses bounded quantifiers; CI runs an adversarial benchmark that feeds pathological input and fails on quadratic blowups.
- Supply chain counts. The library has zero runtime dependencies. The SHA-256/HMAC primitives are implemented in-repo and verified against FIPS 180-4 and RFC 4231 test vectors. Releases are built by GitHub Actions and provenance-signed on npm.
## Rule 3: sometimes you need the secret back
The newest place secrets leak is LLM prompts. You can't just mask them — the model's reply references the values.
import { wrapOpenAI } from 'flare-redact/llm';
const openai = wrapOpenAI(new OpenAI());
// prompts are redacted before leaving your process,
// replies come back with the real values restored
Placeholders are opaque HMAC tokens, consistent per value, so "send it to the same email" still works. The mapping lives in a vault in your process — optionally persisted with AES-256-GCM.
## A war story about provenance
Mid-release, we transferred the repo to a GitHub organization. The next publish failed with E422: npm's provenance check refused the package because repository.url still pointed to the old owner, while
the signed build attestation said the new one.
Annoying? Slightly. But it's the system working: provenance means the npm page cryptographically proves which repo and workflow built the tarball. If your supply chain can't survive a rename, it can't
survive an attacker either. Turn it on for your packages: npm publish --provenance.
## Try it
npm install flare-redact
import { redact } from 'flare-redact';
redact('User alice@corp.com paid with 4242 4242 4242 4242');
// → 'User a***@*** paid with **** **** **** 4242'
It's MIT, TypeScript, Node 20+/browser/edge. If you can construct a false positive, open an issue — the detector suite grows by counter-example: https://github.com/flare-collection/flare-redact
Top comments (0)