Rubric: PII stripping
Written by a person. Last read by a person on 2026-09-05, 3 days ago. Its facts were checked by the eval suite on 2026-09-07.
Enforced by check_stripper, and by the tests in tests/js/strip.test.mjs.
The claim
Text a reader submits is cleaned of personal and secret data in their own browser, before anything is transmitted, and the stripper refuses rather than passing text through when it cannot do that.
Observable evidence
- The categories named in spec 3.7, and whether the module handles each: emails, tokens and keys by pattern and by entropy, file paths containing usernames, IP addresses, and secret-format matches.
- What the module does when given something that is not text.
- Whether every removal is reported back to the reader.
The pass bar
Every spec 3.7 category is handled. A non-string throws rather than being guessed at. Every removal appears in the report, with a count, so a reader can see what went before they send.
Why this rubric exists
This module is the only thing between somebody pasting a stack trace into a help form and that stack trace reaching a public issue with their key in it. Its failure is silent, is discovered by strangers, and cannot be taken back.
That shapes two decisions. It fails closed: if it cannot run, nothing is sent, because a partial strip is worse than no feature at all when the reader believes the feature worked.
It over-removes on purpose. A false positive costs one confusing redaction in text the reader can see and edit. A false negative puts a credential somewhere public. The two are not comparable, and every judgment here is made in that direction.
Ambiguous cases
A secret with no recognizable prefix is why the last rule exists. Patterns cover the vendors somebody thought of; a long unbroken run covers the ones nobody did.
Entropy alone was not enough, and a reader found the case that proved it:
930834098098sf098s098dasf098 looks exactly like a key and scores 2.83, because entropy
measures variety and a secret made mostly of digits has little. Shape counts too. A run of
twenty or more characters mixing digits and letters is not a word in any language, and the cost
of being wrong is one visible redaction in text the reader can still edit.
A JWT is removed as one credential rather than three fragments. The entropy rule would find each of its parts, and three redactions in a row read as noise rather than as one thing having been taken out.
A home directory keeps its shape and loses the username. The path is the useful part of a
stack trace and the username is the personal part, so /home/[removed]/code/app.py says what
the reader needed to say.
A name written in prose is not reachable this way, and neither is an address, or an internal hostname that looks like a word. Patterns and entropy cannot see them. The control that covers them is the reader confirming what is about to be sent, which spec 3.7 requires and which this module does not replace.