prompt-scrub v1.4.0: encrypt local session files at rest #120
will-lamerton
announced in
Annoucements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Built by the Nano Collective, a community collective building AI tooling not for profit, but for the community.
prompt-scrubv1.4.0 ships opt-in encryption for the session files that map placeholders back to your real values. The motivating problem was uncomfortable and overdue: a session file holds the placeholder-to-original map, and v1 left it on disk as plain JSON protected only by0600file permissions. A stolen laptop, a synced backup, or any other process running as the same user could read the mappings in the clear. v1.4.0 makes that opt-in fix available with one config flag, and a typed error path for the cases where it matters.What changed
Setting
"encryptionEnabled": truein the config file makes every session write an AES-256-GCM envelope: a per-file random salt and IV, a 32-byte key derived through scrypt (N=16384, r=8, p=1), and a GCM auth tag that makes tampering detectable rather than silently decodable.Keys are resolved in a fixed order:
setCachedEncryptionKey()).PROMPT_SCRUB_KEYenvironment variable.The interactive prompt refuses to run when stdin or stdout is redirected, so a piped or CI invocation fails with a clear message instead of hanging on a TTY that is not there. Enabling encryption for the first time asks for the passphrase twice and aborts on a mismatch, because a typo at that point would permanently lock the session.
Library callers get a small set of new exports at the package root:
getEncryptionKey(),setCachedEncryptionKey(),getCachedKey(),clearCachedEncryptionKey()encryptSession(),decryptSession(),isEncryptedEnvelope()SessionDecryptionError(typed; distinguishes wrong key, tampered file, and no key available)Derived keys are cached per
(passphrase, salt, KDF params)tuple, soscrub/rehydratedo not pay the deliberately expensive scrypt cost on every read and write.clearCachedEncryptionKey()wipes the passphrase and the derived material together.Migrating existing plaintext sessions
A new command,
prompt-scrub sessions encrypt [id], migrates sessions that are already on disk.idis optional and defaults to all sessions; pass a specific id to scope the run.--rekeyrotates the passphrase over files that are already encrypted. The command refuses to run unlessencryptionEnabledis set, never fabricates a file for a session id that does not exist, and reports how many sessions it encrypted, skipped, and could not find.sessions listandsessions showask for a key only when the file they are about to read is actually encrypted. Turning the flag on does not start demanding a passphrase for plaintext sessions. An undecryptable session inlistis reported on that row rather than aborting the whole listing.A worked example:
The migration is offline: it reads each session file, encrypts it under the supplied key, atomically replaces the original, and prints a one-line summary. There is no upload, no network round-trip, and no remote state.
Behaviour change worth flagging
Reading an encrypted session that cannot be decrypted now throws the typed
SessionDecryptionError, distinguishing "wrong key", "tampered file", and "no key available", instead of quarantining the file and returning an empty map. The previous behaviour looked identical to a session that had simply expired, which made real failures invisible. Silent quarantine is still the behaviour for genuinely unparseable JSON, where the file is corrupt rather than the key being wrong.Writes do not downgrade. Once a session file on disk is encrypted, later writes to it stay encrypted even if
encryptionEnabledis toggled back off, so flipping the flag cannot quietly rewrite a protected map as plaintext. If you want to roll encryption back deliberately, the path issessions encrypt --rekeyto a new plaintext state, then turn the flag off and let a fresh session map itself.Encryption is off by default, and existing plaintext sessions keep working untouched. Nothing in v1.4.0 forces an upgrade path; the only reason to turn the flag on is to defend the on-disk map, and the only reason to migrate existing sessions is to bring them under that same defence.
Notes on the threat model
This release narrows one specific gap: an attacker who reaches the session file on disk no longer gets the placeholder-to-original mappings in the clear. It does not address the rest of the threat surface, and the Threat Model still describes what is and is not defended in one place. A user who believes this tool makes them anonymous is worse off than one who never used it, because they stop reading their prompts and trust the defaults. Always run
inspectfirst.Install
Source, full docs, and the Threat Model live at the repo:
https://github.com/Nano-Collective/prompt-scrubber
Credits
This release shipped thanks to @akramcodez. Closes #94.
Issues and PRs are welcome at the repo. There is also a Nano Collective Discord for the wider conversation about what the collective is building and why.
All reactions