A blocklist asks “does this look like a secret?” An allowlist asks “was this explicitly chosen for publication?” Only the second one is safe, because only the second one is still correct after somebody adds a field upstream.
The exporter that produces this site’s data has three independent layers:
- Structural pick. Every object in the output is constructed field by field from a literal. Nothing is spread, nothing is copied wholesale. A new field added to an upstream record cannot appear here by accident — someone has to type its name into the exporter.
- Content scan. The serialized output is regex-scanned for credentials, internal identifiers, absolute paths, email addresses, and client names before anything is written. One hit aborts the run and writes nothing.
- Shape check. The top-level key set of the output must equal a hardcoded allowlist, or the build throws.
And the tests check the scanner as hard as they check the output — a scanner whose patterns silently stopped matching would pass a “the file is clean” test forever while protecting nothing. So the suite feeds it deliberate poison and asserts that it bites.
The origin story
While building this very page, the exporter was extended to read the project’s 13-week plan out of a YAML config. One of the goals in that file was written as:
- Content production running: <client> posting on cadence, weekly posts
Unquoted, with a colon. YAML parses that as a map, not a string. The
exporter’s code said String(goal) — and String({...}) is "[object Object]".
The scanner dutifully examined the text [object Object], found no client name
in it, and passed.
Nothing leaked: the mangled text was useless rather than sensitive. But the path was a bypass — real text had been replaced with a placeholder before the security check ran, so the check was inspecting a string that no human ever wrote. The fix renders every value back to the text a person actually typed before scanning it, and anything that can’t be is JSON-stringified so the scanner still sees every character.
Fail-closed only works if the thing being checked is the thing being published.