Stop guessing whether a clip is a secret - #21
Merged
Merged
Conversation
The heuristics scanned every copy for PEM blocks, JWTs, key prefixes, connection strings and high-entropy text, and prompted on a match. They went for three reasons. They interrupted an ordinary workflow to report something the user already knew. Copying a credential is a normal thing to do, and the prompt arrived every time, asking permission for the thing the person had just deliberately done. The premise was weaker than it looked. The guessing defended against exposure, but nothing Spool holds leaves the machine. What Spool does change is persistence: a clipboard entry that would have lived until the next copy instead lives in an encrypted file with a visible preview. That is a real difference and it is the honest case for asking — it is not a strong enough one to justify asking about every API key a developer copies. And it was the entire cost of capture: 147ms per MiB, because each needle walked the whole buffer separately. Classification is now 0.003ms, because it no longer reads the content at all — classify does not take the bytes any more, which is the strongest form that claim can take. Two tests that failed intermittently at a five-second timeout stopped being flaky as a side effect. What is kept is not a guess. CanIncludeInClipboardHistory = 0 is an explicit statement from the application that owns the secret, and Windows' own Clipboard History obeys it. Spool makes a transient thing durable, so ignoring it would persist exactly what a password manager asked it not to, and behave worse than the OS feature beside it. It costs a flag check. detect/bytes.ts loses nine functions that existed only to feed the heuristics. wipe stays: a declined clip must not be left in memory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Removes the content heuristics. Keeps the declared signal.
Why the guessing went
It interrupted an ordinary workflow to report something the user already knew. Copying a credential is a normal thing to do, and the prompt arrived every time — asking permission for the thing the person had just deliberately done.
The premise was weaker than it looked. The heuristics defended against exposure, but nothing Spool holds leaves the machine; that is the whole product. What Spool genuinely changes is persistence — a clipboard entry that would have lived until the next copy instead lives in an encrypted file with a visible preview. That is a real difference, and it is the honest case for asking. It is not a strong enough one to justify asking about every API key a developer copies.
It was the entire cost of capture.
Each needle —
sk-,AKIA,-----BEGIN,Password=, and the rest — walked the whole buffer separately.classifyno longer takes the bytes at all, which is the strongest form the "Spool does not read your clips" claim can take.Two tests that failed intermittently at a five-second timeout stopped being flaky as a side effect. That was the symptom that started this, not the reason.
Why the declared signal stays
CanIncludeInClipboardHistory = 0is not a guess. It is an explicit statement from the application that owns the secret, saying do not persist this, and Windows' own Clipboard History obeys it. Spool makes a transient thing durable, so ignoring that request would persist exactly what a password manager asked it not to — and leave Spool behaving worse than the OS feature sitting beside it. It costs a flag check and no scanning.The prompt keeps one voice now: it always names the application, because the application is the only thing that can raise it. There is no softer wording for a guess, because there are no guesses.
What went
looksLikeSecret, the entropy machinery,HEURISTIC_RULES, and theTiertypedetect/bytes.tsthat existed only to feed them —ascii,startsWith,includes,indexOf,trim,isDigit,hasWhitespace,characterClasses,shannonEntropywipestays: a declined clip must not be left in memoryThe privacy screens now say plainly that Spool does not inspect what you copy, which is true in a way it previously was not.
Verification
352 tests, typecheck, lint, and the zero-network gate pass.
Note
Branched off
clip-selection(#20), which is based onrepeat-unspool(#19). Merge order: #19, #20, then this.🤖 Generated with Claude Code