security: redact secrets on the explicit add paths (#179)#181
Merged
Conversation
The explicit write paths — `recall add` (CLI) and `memory_add` (MCP) — persisted free-text directly into SQLite with no redaction, so a known-prefix credential typed by the user was stored in cleartext. Wire the existing `scrub()` seam (src/lib/write-safety.ts) into the single choke point both surfaces route through: addDecision / addLearning / addBreadcrumb in src/lib/memory.ts. Every persisted free-text field is scrubbed before insert; structured/enum fields are left untouched. Redacted kinds (never the values) are surfaced via an optional out-arg — a warning line on the CLI and an appended notice in the memory_add response — so redaction is visible-by-design, not silent. Choke-point wiring (vs. per-surface) means any future write path that calls these functions is covered too, and keeps the `number` return so no existing caller changes. Mirrors the session-extract precedent in hooks/lib/extract-core.ts. Tests assert redaction + kind-surfacing on both `recall add` and the three add* fns, and that ordinary prose is stored unchanged. Closes #179
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.
What
Wire the existing
scrub()redaction seam into the explicit memory write paths so known-prefix credentials are no longer persisted in cleartext.Before this change,
recall add(CLI) andmemory_add(MCP) inserted user free-text straight into SQLite with no redaction. A credential with a recognizable prefix (provider API key, bearer token, AWS access-key id, JWT, etc.) typed by the user was stored verbatim indecisions/learnings/breadcrumbs. The redaction layer that already runs on session ingestion simply did not run here. Pre-existing gap — not introduced by #156.How
addDecision/addLearning/addBreadcrumbinsrc/lib/memory.ts. A smallscrubFreeTexthelper there scrubs every persisted free-text field (decision/reasoning/alternatives · problem/solution/prevention · breadcrumb content) before insert, via the canonicalscrub()re-exported atsrc/lib/write-safety.ts(the chore: promote write-safety scrub() pattern table into src/lib (DRY across CLI + MCP) #50 seam). Structured/enum fields (category, status, confidence, tags, importance, provenance) are never touched. Mirrors the session-extract precedent inhooks/lib/extract-core.ts.number; redacted kinds are surfaced through an optional out-arg, so none of the ~40 existing callers change.⚠ redacted secrets before storing: …line on the CLI after the✓ Added …line, and an appended notice in thememory_addresponse. Kinds are aggregated distinct across a record's fields, reported once.[REDACTED:<kind>]form, so search still finds the surrounding context.This is the anchored known-prefix layer only. It does not touch the #156 threat-detect (entropy/injection) layer, nor the extraction paths that already scrub.
Tests
New
tests/commands/scrub-add-path.test.ts(disposable, obviously-fake fixtures — repeated-char filler, never real values):recall add(runAdd*) and the threeadd*fns (thememory_addpath).Verification
bun run lint— cleanbun test— 1174 pass / 0 fail (10 new)Closes #179