Tag the known fakes once, keep the alarm honest

If you ever asked an agent to write an AWS example, your transcripts hold AKIAIOSFODNN7EXAMPLE. It is the key from Amazon's own docs, it matches the AWS pattern perfectly, and spillscan reported it on every run. So did the fixture token in your test suite and the JWT from a tutorial you pasted. After the third time you see the same harmless line, you start reading the report less carefully. An alarm that cries wolf trains you to ignore it.

spillscan now reads an allowlist. The interesting part is what you put in it.

A fingerprint, not the value

Every finding now has an FP column: the first 12 hex characters of a SHA-256 over the value, with a spillscan-specific prefix mixed in. It identifies the value without containing it.

$ spillscan scan
RULE        PREVIEW    FP            AGENT        FILE:LINE
aws-akia    AKIA…MPLE  8cc03843ecd0  claude-code  ~/.claude/projects/…/x.jsonl:128
github-pat  ghp_…a91F  1d6e40b2c9f7  claude-code  ~/.claude/projects/…/x.jsonl:128
...
  Known-fake value? Add the line fp:<FP> to ~/.config/spillscan/allow.txt; scan and redact then skip it.

Copy the one you recognise into ~/.config/spillscan/allow.txt:

fp:8cc03843ecd0   # AWS docs example key

Why not just let people list the value? Because the allowlist is exactly the file you will commit to dotfiles, share with a teammate, or paste into an issue. If it held values, the first time someone allowlisted a key they believed was fake, the list would become a new place where a real secret leaks. With a fingerprint, the worst case is a 12-character hash. A value: key exists for literals that are fake by design, and the docs say plainly that it stores what you type.

Rules and places, too

Sometimes the noise is a whole class: every JWT in the sessions where you worked on an auth tutorial, say. Keys on one line must all match; separate lines are alternatives.

rule:jwt path:~/.claude/projects/*auth-tutorial*/**
path:~/.codex/sessions/2026/01/**
rule:generic-assign

Globs work on the absolute transcript path: * stays in one directory, ** crosses them, ~/ is home, and a glob with no slash matches just the file name. A typo such as rule:jtw stops the run with allow.txt:1: unknown rule "jtw" (did you mean rule:jwt?). An allowlist that silently matches nothing is worse than none.

Nothing goes quiet without a trace

Hiding findings is the risky half of this feature, so spillscan is loud about it. The header says allowlisted=1, a closing line names the list that did it, and spillscan scan --no-allow shows the raw reading. Allowlisted findings never cause exit 2, so a CI check can go green, but --json still reports the count. redact leaves the same values exactly as they were and says how many. The MCP scan_report follows your default list, and it is still read-only.

Extra lists come in with --allow FILE, repeatable. The follow-up commands scan prints repeat them, so the scrub you copy skips exactly what the survey hid.

One bug the tests caught

A PEM private key spans several lines. In the JSONL file those line breaks are stored as \n escapes; once the JSON is decoded they are real newlines. Scan fingerprints the raw bytes and redact walks the decoded JSON, so the same key got two different fingerprints, and an allowlisted PEM block would have been scrubbed anyway. Redact now checks both forms. There is a test that fails if that check is removed.

This is on main and ships in the next release. Format details are in Configuration; source and README. And a known fake is the only thing to allowlist. A real key that leaked still needs rotating.

— 2026-10-28