residoo 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +225 -46
  2. package/SECURITY.md +29 -22
  3. package/package.json +1 -1
  4. package/src/cli.js +82 -16
  5. package/src/integrity.js +669 -0
  6. package/src/patterns.js +78 -5
  7. package/src/report.js +74 -7
  8. package/src/sources/agent-configs.js +308 -0
  9. package/src/sources/aider.js +361 -0
  10. package/src/sources/amazon-q.js +199 -0
  11. package/src/sources/antigravity-cli.js +155 -0
  12. package/src/sources/cline.js +208 -0
  13. package/src/sources/codebuff.js +295 -0
  14. package/src/sources/codex-cli.js +258 -0
  15. package/src/sources/cody.js +325 -0
  16. package/src/sources/continue.js +408 -0
  17. package/src/sources/copilot-chat.js +272 -0
  18. package/src/sources/copilot-cli.js +300 -0
  19. package/src/sources/crush.js +364 -0
  20. package/src/sources/cursor.js +374 -0
  21. package/src/sources/devin-cli.js +241 -0
  22. package/src/sources/factory-droid.js +153 -0
  23. package/src/sources/fx.js +136 -0
  24. package/src/sources/gemini-cli.js +242 -0
  25. package/src/sources/goose.js +366 -0
  26. package/src/sources/grok-cli.js +267 -0
  27. package/src/sources/hermes.js +282 -0
  28. package/src/sources/index.js +172 -8
  29. package/src/sources/jetbrains-ai-assistant.js +343 -0
  30. package/src/sources/jetbrains-junie.js +292 -0
  31. package/src/sources/kilo-code.js +430 -0
  32. package/src/sources/kimi-code.js +147 -0
  33. package/src/sources/kiro-cli.js +393 -0
  34. package/src/sources/kiro-ide.js +230 -0
  35. package/src/sources/llm.js +328 -0
  36. package/src/sources/mentat.js +143 -0
  37. package/src/sources/open-interpreter.js +224 -0
  38. package/src/sources/openclaw.js +218 -0
  39. package/src/sources/opencode.js +379 -0
  40. package/src/sources/openhands.js +181 -0
  41. package/src/sources/pearai.js +151 -0
  42. package/src/sources/pi-agent.js +130 -0
  43. package/src/sources/qodo-gen.js +189 -0
  44. package/src/sources/qwen-code.js +244 -0
  45. package/src/sources/roo-code.js +239 -0
  46. package/src/sources/trae.js +294 -0
  47. package/src/sources/void.js +273 -0
  48. package/src/sources/warp.js +395 -0
  49. package/src/sources/windsurf.js +256 -0
  50. package/src/sources/zed.js +374 -0
package/README.md CHANGED
@@ -1,13 +1,29 @@
1
- # residoo
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="docs/logo-dark.svg">
5
+ <source media="(prefers-color-scheme: light)" srcset="docs/logo-light.svg">
6
+ <img src="docs/logo-light.svg" alt="residoo" width="280">
7
+ </picture>
2
8
 
3
9
  **Find secrets leaking through your AI coding agent's session history.**
4
10
 
11
+ [![npm version](https://img.shields.io/npm/v/residoo)](https://www.npmjs.com/package/residoo)
12
+ [![CI](https://github.com/dandovdub/residoo/actions/workflows/ci.yml/badge.svg)](https://github.com/dandovdub/residoo/actions/workflows/ci.yml)
13
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
14
+ [![node >=18](https://img.shields.io/badge/node-%3E%3D18-339933)](package.json)
15
+ [![runtime dependencies: 0](https://img.shields.io/badge/runtime_dependencies-0-brightgreen)](package.json)
16
+
17
+ <img src="docs/demo.svg" alt="residoo scan terminal output: 17 potential secrets found across 3 files, 87 files scanned (1.2 GB), values redacted to first/last 4 characters, no network calls" width="760">
18
+
19
+ </div>
20
+
5
21
  Every time Claude Code, Cursor, or a similar tool reads a file, runs a command, or
6
- browses a page on your behalf, it writes a transcript of the whole session to disk —
7
- including the contents of whatever it touched. If that ever included a `.env` file,
8
- a config with a real key in it, or a login token captured during testing, that
9
- credential is now sitting in plaintext, indefinitely, in a place almost nobody
10
- thinks to check.
22
+ browses a page on your behalf, it writes a transcript of the whole session to
23
+ disk, including the contents of whatever it touched. If that ever included a
24
+ `.env` file, a config with a real key in it, or a login token captured during
25
+ testing, that credential is now sitting in plaintext, indefinitely, in a place
26
+ almost nobody thinks to check.
11
27
 
12
28
  residoo scans those transcripts and tells you what's in them.
13
29
 
@@ -21,31 +37,149 @@ $ residoo scan
21
37
  16 [high] AWS Access Key ID (1 distinct value, re-exposed 15× across tool output)
22
38
  1 [high] Private key block
23
39
 
24
- Values are redacted in this report first/last 4 characters only. Nothing scanned
25
- here left your machine; residoo makes no network calls.
40
+ Values are redacted in this report (first/last 4 characters only). Nothing
41
+ scanned here left your machine; residoo makes no network calls.
26
42
  ```
27
43
 
28
44
  ## Why this, and not a git secret scanner
29
45
 
30
- Tools like `gitleaks` and `trufflehog` are excellent at what they do and what
46
+ Tools like `gitleaks` and `trufflehog` are excellent at what they do, and what
31
47
  they do is scan **commits**. That's a different, well-covered space. Nobody was
32
48
  looking at the **conversation transcripts** these agents leave behind, which
33
49
  contain a superset of everything a commit does: not just code, but file
34
50
  contents, terminal output, and whatever got pasted into a prompt.
35
51
 
52
+ Two newer categories are adjacent but solve a different problem, worth being
53
+ precise about rather than lumping together:
54
+
55
+ - **Real-time hooks** (e.g. GitGuardian's `ggshield` AI hook, GitHub's secret
56
+ scanning via its MCP server) intercept a prompt or a code change *as it
57
+ happens*, going forward, in the session that has the hook installed. They
58
+ do nothing for the months of transcripts already sitting on disk, or for
59
+ any session run without the hook active. residoo scans **retroactively, at
60
+ rest**: every file already there, from every past session.
61
+ - **agentsweep** is a genuine, welcome peer covering similar ground. Broader,
62
+ in fact: 31 agent sources and 209 detection rules to residoo's smaller set,
63
+ plus in-place redaction, SARIF output, and a pre-commit hook. The tradeoffs
64
+ are worth naming precisely rather than either dismissing it or copying it
65
+ blindly. It needs Python 3.11+ and three pip packages (all clean ones, on
66
+ inspection; no known CVEs), where residoo needs nothing beyond Node. Its
67
+ own README documents that its in-place redaction leaves the pre-redaction
68
+ original sitting in a **plaintext** `.bak` file, and its issue tracker shows
69
+ the real cost of that design: a merged fix
70
+ ([PR #13](https://github.com/Ishannaik/agent-sweep/pull/13)) for a case
71
+ where redacting a WAL-mode SQLite database left the secret recoverable from
72
+ a leftover journal file. residoo's `--seal` takes a different tradeoff
73
+ (encrypt a copy, touch nothing, never claim a file is "cleaned") precisely
74
+ to avoid that failure class. Its tracker also shows several real,
75
+ since-fixed false-*clean* reports: schema drift and malformed lines
76
+ silently skipped, `--root` pointed at a file scanning nothing and exiting
77
+ 0. That is the exact failure mode residoo's `broken`/`partial` status
78
+ contract (see `CONTRIBUTING.md`) exists to make structurally hard to
79
+ reproduce. None of this makes agentsweep bad; it makes for a legitimately
80
+ different set of choices, and its README is honest about its own tradeoffs
81
+ too. Worth a look if broader source coverage matters more to you than a
82
+ minimal dependency footprint.
83
+
84
+ This isn't a gap Anthropic is planning to close upstream, either: a
85
+ [request to scrub secrets from `~/.claude/projects` natively](https://github.com/anthropics/claude-code/issues/50014)
86
+ was filed and closed as **not planned**. Whatever scans this directory, it
87
+ won't be built into the tool that writes it.
88
+
36
89
  ## What it does
37
90
 
38
91
  - Scans your local AI-agent session transcripts for high-confidence secret
39
- patterns (cloud provider keys, private key blocks, OAuth/API tokens,
40
- database connection strings, and more see `src/patterns.js`).
92
+ patterns: cloud provider keys, private key blocks, OAuth/API tokens,
93
+ database connection strings, and more (see `src/patterns.js`).
41
94
  - Redacts everything in its own output. You get a shape and a first/last-4
42
- preview, never the real value including in `--json` mode.
95
+ preview, never the real value, including in `--json` mode.
43
96
  - Tells you how many **distinct** secrets it found versus how many times one
44
97
  got echoed back across tool calls, so the headline number reflects real
45
98
  exposure, not repetition.
46
99
  - Flags likely placeholder/example matches (an HTML form's
47
100
  `placeholder="AKIA..."` hint, a doc's example key) separately from real
48
101
  findings, rather than either hiding them or inflating the count with them.
102
+ - Scans agent **config** files too (settings, MCP server configs, memory
103
+ files), and checks the places the 2026 supply-chain campaigns planted
104
+ persistence: hooks, dropper scripts, auto-run tasks, invisible Unicode.
105
+ See the next section.
106
+
107
+ ## Beyond transcripts: configs and planted persistence
108
+
109
+ Transcripts leak what your agent *saw*. Config files leak what your agent was
110
+ *configured with*, and it turns out that is the better-measured problem.
111
+ GitGuardian counted 24,008 secrets inside MCP config files on public GitHub
112
+ (2,117 still valid when checked), and Lakera found live credentials inside
113
+ `.claude/settings.local.json` files shipped in roughly 30 published npm
114
+ packages, because Claude Code's approved-command cache quietly accumulates
115
+ tokens and no packaging tool ignores `.claude/` by default. So as of v0.2.0,
116
+ `residoo scan` includes an **agent config source** covering the home-level
117
+ config files of Claude Code, Claude Desktop, Cursor, Gemini CLI, Codex, and
118
+ Kiro. Every path is verified against a real install or published sources (one
119
+ disclosed exception, a stealer-target path backed by a single published
120
+ list, argued openly in the source header), with the full verification trail
121
+ written into `src/sources/agent-configs.js`.
122
+
123
+ The same files are also where the year's supply-chain campaigns planted
124
+ their persistence. Mini Shai-Hulud wrote a `SessionStart` hook into
125
+ `.claude/settings.json` and a `"runOn": "folderOpen"` task into
126
+ `.vscode/tasks.json`. Miasma reused both plants and added
127
+ `.gemini/settings.json` hooks and `.cursor/rules/setup.mdc` prompt-injection
128
+ files. The keyv/ChainDrop wave dropped a script literally named `setup.mjs`
129
+ into `.claude/` and `.vscode/`. And TrapDoor hid instructions in
130
+ `CLAUDE.md`/`.cursorrules` as zero-width Unicode: invisible in your editor,
131
+ fully visible to the agent. So every scan now also runs **integrity checks**
132
+ over those exact locations:
133
+
134
+ - Every auto-executing hook found in the checked locations is listed (hooks
135
+ run without asking; you should be able to vouch for each one). Only
136
+ commands matching a published campaign IOC (`setup.mjs`) or a
137
+ campaign-shaped behavior escalate to warnings: piping a download straight
138
+ into a shell, decoding base64 before executing, running repo-local scripts
139
+ out of dot-directories.
140
+ - Loose scripts in `.claude/`, and the exact planted filenames from the
141
+ published IOC lists, are flagged by name.
142
+ - `CLAUDE.md`, `.cursorrules`, and `.cursor/rules/*` are checked for
143
+ zero-width Unicode, with legitimate emoji/script joiners kept to an
144
+ informational tier so the warning count stays meaningful.
145
+ - `.vscode/tasks.json` is parsed (as JSONC, comments and all) for tasks that
146
+ execute on folder open.
147
+
148
+ The checks are read-only like everything else, warnings (not review items)
149
+ count toward `--fail-on-find`, project-level checks cover the directory you
150
+ run from, and `--no-integrity` skips the whole thing. A config that exists
151
+ but can't be read or parsed is reported as unverified, never silently
152
+ counted as clean.
153
+
154
+ ## How it works
155
+
156
+ ```
157
+ YOUR MACHINE · no network calls
158
+ ┌───────────────────────────────────────────────────────────────┐
159
+ │ │
160
+ │ 42 transcript sources agent config files │
161
+ │ ~/.claude, Cursor, Codex… settings · MCP · memory │
162
+ │ │ │ │
163
+ │ ├──────────────┬───────────────┤ │
164
+ │ ▼ │ ▼ │
165
+ │ stream + match │ integrity checks │
166
+ │ 35 verified rules │ hooks · droppers · │
167
+ │ │ │ zero-width unicode │
168
+ │ ▼ ▼ │ │
169
+ │ redacted report (first/last 4 chars only) ◀────────────┤
170
+ │ │ │
171
+ │ ▼ --seal (only if you ask) │
172
+ │ AES-256-GCM vault · scrypt key · encrypted manifest │
173
+ │ │ │ │
174
+ │ ▼ unseal --restore ▼ --upload-cloudroam
175
+ │ SHA-256 verified copy ciphertext only ┄┄┄┄┄┄┄┄┄▶
176
+ │ │
177
+ └───────────────────────────────────────────────────────────────┘
178
+ ```
179
+
180
+ The `--seal` and `--upload-cloudroam` legs never run unless you pass their
181
+ flag. Everything above the vault happens on every scan; nothing in the
182
+ diagram ever modifies or deletes an existing file.
49
183
 
50
184
  ## Sealing what it finds
51
185
 
@@ -57,29 +191,31 @@ residoo scan --seal
57
191
  ```
58
192
 
59
193
  Every transcript that carried a finding is encrypted into a local vault
60
- directory AES-256-GCM, key derived from your passphrase with scrypt, streamed
61
- (an 800MB transcript never touches memory whole). The vault's manifest — the
62
- mapping from numbered blobs back to real paths is itself encrypted, so the
63
- vault doesn't advertise what's inside it even by name. **Originals are never
64
- touched**: once you've verified a restore works (`residoo unseal <vault> --restore
65
- 0001.sealed --out /tmp/check` verified byte-identical via a recorded SHA-256),
66
- deleting the plaintext is your decision, made by you, not by this tool.
194
+ directory. AES-256-GCM, key derived from your passphrase with scrypt,
195
+ streamed, so an 800MB transcript never touches memory whole. The vault's
196
+ manifest (the mapping from numbered blobs back to real paths) is itself
197
+ encrypted, so the vault doesn't advertise what's inside it even by name.
198
+ **Originals are never touched.** Once you've verified a restore works
199
+ (`residoo unseal <vault> --restore 0001.sealed --out /tmp/check`, verified
200
+ byte-identical via a recorded SHA-256), deleting the plaintext is your
201
+ decision, made by you, not by this tool.
67
202
 
68
203
  Optionally, `--upload-cloudroam` (with `CLOUDROAM_API_KEY`, `--connector`,
69
204
  `--bucket`) copies the sealed vault to [CloudRoam](https://cloudroam.io) for
70
- durable, cross-cloud storage. **This is the only feature in residoo that touches
71
- the network, it never runs unless you pass the flag, and only ciphertext is
72
- transmitted** the vault is sealed before upload code ever executes.
205
+ durable, cross-cloud storage. **This is the only feature in residoo that
206
+ touches the network, it never runs unless you pass the flag, and only
207
+ ciphertext is transmitted.** The vault is sealed before upload code ever
208
+ executes.
73
209
 
74
210
  ## What it does not do
75
211
 
76
- - **No network calls in the default path and none at all unless you
212
+ - **No network calls in the default path, and none at all unless you
77
213
  explicitly pass `--upload-cloudroam`.** A secret scanner that phones home is
78
214
  not a tool you should trust with your secrets. Verify this yourself: the one
79
215
  `fetch` call in the codebase is in `src/sealvault.js`, reachable only behind
80
216
  that flag, and sends only encrypted bytes.
81
217
  - **Nothing destructive, ever.** Scanning is read-only. Sealing creates *new*
82
- files and modifies or deletes nothing not even the plaintext it just
218
+ files and modifies or deletes nothing, not even the plaintext it just
83
219
  encrypted a copy of. That last step is deliberately left to a human.
84
220
  - **No telemetry, no analytics, no update-check ping.**
85
221
 
@@ -96,7 +232,10 @@ npm install -g residoo
96
232
  residoo scan
97
233
  ```
98
234
 
99
- Requires Node.js 18+. Zero runtime dependencies check `package.json`.
235
+ Requires Node.js 18+. The SQLite-backed sources listed below additionally
236
+ need 22.5+; residoo still runs and scans every line-delimited/JSON source,
237
+ including Claude Code, fine without it. Zero runtime dependencies, and you
238
+ can check `package.json` rather than take that on faith.
100
239
 
101
240
  ## Usage
102
241
 
@@ -106,7 +245,9 @@ residoo scan [options]
106
245
  --json machine-readable output (full detail, still redacted)
107
246
  --include-noisy also run broad, false-positive-prone rules
108
247
  --include-suppressed also show matches that looked like placeholder/example text
109
- --fail-on-find exit code 1 if anything is found (for CI)
248
+ --fail-on-find exit code 1 if anything is found (for CI): secret
249
+ findings and integrity warnings count, review items don't
250
+ --no-integrity skip the integrity checks
110
251
  --no-color disable ANSI colour
111
252
 
112
253
  --seal encrypt every transcript with findings into a local vault
@@ -119,48 +260,86 @@ residoo unseal <vault-dir> --restore <n> --out <p> restore one file, hash-verif
119
260
  ```
120
261
 
121
262
  The vault passphrase comes from `RESIDOO_PASSPHRASE` or a hidden interactive
122
- prompt. There is no recovery if you lose it that is the point of the design,
263
+ prompt. There is no recovery if you lose it. That is the point of the design,
123
264
  so pick one you keep.
124
265
 
125
266
  ## Sources supported today
126
267
 
127
- **Claude Code** (`~/.claude/projects/**/*.jsonl`) verified against real,
128
- populated transcript directories while building this.
129
-
130
- Cursor, GitHub Copilot, and Windsurf all keep local session history too, and
131
- support for them is very much wanted — but shipping a scanner that checks a
132
- guessed path and reports "all clear" when it simply didn't know where to
133
- look is worse than not supporting a tool at all. If you use one of these and
134
- want to add a verified adapter, see below — it's a small, self-contained
135
- file.
268
+ 43 sources as of this writing (42 transcript stores plus the agent-config
269
+ source described above), in two honestly-distinct tiers. See
270
+ `src/sources/index.js` for the full list and grouping, and each source file's
271
+ own header for exactly what was and wasn't checked.
272
+
273
+ **Real-install-verified.** The adapter was run against an actual, populated
274
+ installation and confirmed to find real content:
275
+
276
+ - **Claude Code** (`~/.claude/projects/**/*.jsonl`)
277
+ - **Agent config files**, for its Claude-family paths (`~/.claude.json` and
278
+ its `.backup`, `~/.claude/settings*.json`, Claude Desktop's
279
+ `claude_desktop_config.json`). Its Cursor/Gemini/Codex/Kiro paths are in
280
+ the tier below; `src/sources/agent-configs.js` tracks verification per
281
+ path, not per file.
282
+
283
+ **Multi-source-corroborated-but-unverified.** The path/schema is backed by
284
+ 2+ independent, credible sources (official docs, the tool's own shipped
285
+ source code, a real community tool that reads the same files for a living,
286
+ or a real user's own reported install) but was **not** checked against a real
287
+ install of the tool on any machine this project was built on. Every adapter
288
+ in this tier is still built to fail loudly (`broken: true`, `status:
289
+ "failed"`) rather than silently report "all clear", but the path itself
290
+ could still be stale or wrong in a way only a real install can catch. If you
291
+ use one of these and can confirm `residoo scan`'s file counts look right for
292
+ what's actually on your disk, that report is exactly what moves a source out
293
+ of this tier:
294
+
295
+ Cursor, Codex CLI, OpenCode, Aider, Cline, Roo Code, Kilo Code, Windsurf,
296
+ PearAI, Trae, Void, Gemini CLI, Qwen Code, Continue, Open Interpreter, Goose,
297
+ GitHub Copilot Chat, GitHub Copilot CLI, `llm` (Simon Willison's Datasette-
298
+ adjacent CLI), Codebuff, Mentat, Hermes, OpenClaw, Warp, Crush, Grok Build,
299
+ Kiro CLI, Kiro IDE, Zed, JetBrains Junie, JetBrains AI Assistant, Sourcegraph
300
+ Cody, Amazon Q Developer, Qodo Gen, OpenHands, Factory Droid CLI, Devin CLI,
301
+ Pi, Google Antigravity, Kimi Code, and `fx`.
302
+
303
+ A few of these are SQLite-backed (Cursor, Crush, Cody, Devin CLI, Hermes,
304
+ Kiro CLI, `llm`, Trae, Void, Warp, Zed) and need Node.js 22.5+ for the
305
+ built-in `node:sqlite` module (not a dependency; see `package.json`). On an
306
+ older Node, `residoo scan` reports each of those as detected-but-not-scanned
307
+ rather than silently dropping it or crashing.
308
+
309
+ **Investigated and deliberately not included**, rather than guessed at:
310
+ Plandex (confirmed, from its own source, to be client-server with nothing
311
+ local to scan), CodeGPT and Augment Code (both account/cloud-based, no
312
+ evidence of a local transcript file), and Replit Agent (confirmed
313
+ cloud-only). Tabby, Tabnine, Zencoder, Tongyi Lingma, and Berd were
314
+ researched but didn't clear this project's 2-independent-source bar in the
315
+ time available. A verified adapter for any of these is a welcome PR.
136
316
 
137
317
  ## Adding a source
138
318
 
139
319
  A source is a small object with four methods: `id()`, `label()`,
140
320
  `available()`, `files()`, and `readLines(file)`. `src/sources/claude-code.js`
141
- is the reference implementation copy it, point it at the real local
321
+ is the reference implementation. Copy it, point it at the real local
142
322
  storage path for your tool, and open a PR. Two contracts scan.js actually
143
323
  depends on, worth getting right rather than guessing from a quick skim:
144
324
 
145
325
  - **`files()`** is a generator yielding `{ file, mtimeMs, sizeBytes, broken }`.
146
326
  Set `broken: true` (other fields can be omitted) for an entry that looked
147
- like it should be scannable but wasn't a dangling symlink is the main
148
- case. Don't just `continue` past it inside the generator: an early version
327
+ like it should be scannable but wasn't; a dangling symlink is the main
328
+ case. Don't just `continue` past it inside the generator. An early version
149
329
  of the Claude Code source did exactly that, and a real, non-hypothetical
150
330
  case (a project directory relocated via a symlink whose target no longer
151
- exists) went completely invisible not in the scan count, not in any
331
+ exists) went completely invisible: not in the scan count, not in any
152
332
  warning, nothing. Surfacing it as `broken` is what lets scan.js report it
153
333
  instead.
154
334
  - **`readLines(file)`** is `async`, returning `{ lines, status, bytesRead }`.
155
335
  `status` is `"complete"`, `"partial"` (some real lines WERE read before a
156
- failure partway through return them, don't discard real content because
336
+ failure partway through; return them, don't discard real content because
157
337
  the rest of the file didn't finish cleanly), `"too-large"`, or `"failed"`.
158
338
  Whatever you return in `lines` for a non-"complete" status still gets
159
339
  scanned normally.
160
340
 
161
341
  Please verify the path actually exists and holds real content before
162
- submitting see the note above on why
163
- that matters here specifically.
342
+ submitting. See the note above on why that matters here specifically.
164
343
 
165
344
  ## A known limitation, stated plainly
166
345
 
@@ -168,7 +347,7 @@ Shape-based detection can't tell a real secret from a realistic-looking
168
347
  example in a fetched web page or a piece of documentation your agent read
169
348
  aloud back to you. The `--include-suppressed`/placeholder-context heuristic
170
349
  catches the common UI-hint case, not every case. Treat every finding as a
171
- lead to check, not a certainty the same is true of every tool in this
350
+ lead to check, not a certainty. The same is true of every tool in this
172
351
  category, including the well-established ones.
173
352
 
174
353
  ## License
@@ -177,9 +356,9 @@ MIT. See `LICENSE`.
177
356
 
178
357
  ---
179
358
 
180
- Built and maintained by the team behind [CloudRoam](https://cloudroam.io)
359
+ Built and maintained by the team behind [CloudRoam](https://cloudroam.io),
181
360
  client-side encrypted, cross-cloud backup. residoo has no dependency on
182
- CloudRoam and never will need one to be useful; if a scan turns up something
361
+ CloudRoam and never will need one to be useful. If a scan turns up something
183
362
  you want stored somewhere durable and encrypted going forward, that's the
184
363
  kind of problem CloudRoam solves, but it's an entirely separate choice from
185
364
  running this tool.
package/SECURITY.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Reporting a vulnerability
4
4
 
5
- If you find a security issue in residoo including "this finding shouldn't
5
+ If you find a security issue in residoo, including "this finding shouldn't
6
6
  have been suppressed," "this output leaked more than it should have," or
7
- anything in the redaction logic please report it privately rather than as
7
+ anything in the redaction logic, please report it privately rather than as
8
8
  a public issue. Open a [GitHub Security Advisory](../../security/advisories/new)
9
9
  on this repository, or email the maintainer listed in `package.json`.
10
10
 
@@ -13,45 +13,47 @@ Please include:
13
13
  - Whether real secret material was involved (if so, a redacted/synthetic
14
14
  reproduction is preferred over the real value)
15
15
 
16
- You'll get an acknowledgment within a few days. There's no bug bounty
17
- this is a small open-source tool, not a funded program but every report
16
+ You'll get an acknowledgment within a few days. There's no bug bounty
17
+ (this is a small open-source tool, not a funded program), but every report
18
18
  gets read and taken seriously, and credited in the fix unless you'd rather
19
19
  stay anonymous.
20
20
 
21
21
  ## What's already been checked, and how
22
22
 
23
23
  This isn't a claim taken on faith. Every property below was tested, not
24
- just asserted see the git history for the actual commands run:
24
+ just asserted. See the git history for the actual commands run:
25
25
 
26
26
  - **No network calls in the scan path.** Grepped for every network-capable
27
27
  primitive (`http`, `https`, `fetch`, `child_process`, etc.) across the
28
28
  scanning code. The codebase's single `fetch` lives in `src/sealvault.js`,
29
29
  is reachable only behind the explicit `--upload-cloudroam` flag, and
30
- transmits ciphertext only the vault is fully sealed before that code
30
+ transmits ciphertext only. The vault is fully sealed before that code
31
31
  can run.
32
32
  - **Scanning is read-only.** Grepped for every filesystem write/delete
33
33
  primitive in the scan path. Sealing (`--seal`) writes NEW files into a
34
34
  vault directory it creates; nothing in the codebase modifies or deletes
35
- an existing file, including the plaintext originals a seal just encrypted —
36
- removing those is deliberately left to the human.
35
+ an existing file, including the plaintext originals a seal just
36
+ encrypted. Removing those is deliberately left to the human.
37
37
  - **Output can't leak more than it shows.** The one raw matched value is
38
38
  used in exactly two places: an in-memory dedup count (never serialized)
39
39
  and the redaction function. Verified with a crafted input containing a
40
- raw ANSI escape sequence that a real terminal would execute confirmed
41
- it rendered live (a working clear-screen) before the fix, confirmed it
42
- doesn't after.
40
+ raw ANSI escape sequence that a real terminal would execute. It rendered
41
+ live (a working clear-screen) before the fix, and doesn't after. The
42
+ integrity checker applies the same discipline to attacker-controlled
43
+ config content: control characters are stripped and invisible Unicode is
44
+ rewritten as visible escapes before anything reaches your terminal.
43
45
  - **Not vulnerable to regex denial-of-service.** Every pattern checked
44
46
  against the nested-quantifier shape behind real, dated CVEs in adjacent
45
47
  tooling (e.g. CVE-2026-0621, a ReDoS in Anthropic's own MCP SDK from
46
48
  catastrophic backtracking on an exploded template pattern). Also stress-
47
49
  tested directly against multi-megabyte adversarial inputs.
48
50
  - **No supply-chain surface.** Zero runtime dependencies, zero
49
- pre/post-install lifecycle scripts check `package.json` yourself,
51
+ pre/post-install lifecycle scripts. Check `package.json` yourself;
50
52
  there's nothing to hide behind a `postinstall` hook.
51
53
 
52
54
  ## Verifying you have the real thing
53
55
 
54
- Fake clones of security tools are a real, active pattern not a
56
+ Fake clones of security tools are a real, active pattern, not a
55
57
  hypothetical. In the last year alone: a self-propagating npm worm that
56
58
  typosquatted common package names and injected malicious config into AI
57
59
  coding tools' own settings files; a fake installer for a well-known AI
@@ -61,15 +63,20 @@ history to smuggle malware behind a README download link. A tool whose
61
63
  entire premise is "trust me with what I find in your secrets" is exactly
62
64
  the kind of thing worth impersonating.
63
65
 
64
- - The only npm package is **`residoo`**, published from **this** GitHub
65
- repository via CI, not uploaded by hand from a maintainer's laptop.
66
- - The canonical repository is **`github.com/dandovdub/residoo`** the one
67
- named in this package's own `repository` field, which npm's provenance
68
- attestation cryptographically ties each release to. A GitHub account named
69
- "residoo" exists and is NOT this project. If you found residoo through a
70
- link, a blog post, or a search result rather than directly on npm, check
71
- the provenance badge on the npm page it names the exact repo and
72
- workflow that built the release.
66
+ - The canonical repository is **`github.com/dandovdub/residoo`**, the one
67
+ named in this package's own `repository` field. A GitHub account named
68
+ "residoo" exists and is NOT this project.
69
+ - The only npm package is **`residoo`**. Releases are published from this
70
+ repository through CI with npm's provenance attestation, which
71
+ cryptographically ties each release to the exact repo and workflow that
72
+ built it; check the provenance badge on the npm page. One honest
73
+ exception, stated rather than hidden: the very first release (v0.1.0)
74
+ was a manual upload to claim the name, so provenance starts at the first
75
+ CI-published version after it.
76
+ - The only PyPI package is **`residoo`**: a thin official launcher whose
77
+ entire job is running the npm CLI via `npx`. Its source lives in this
78
+ repository under `pypi/`. It exists partly so nobody else can hold the
79
+ name.
73
80
  - Nothing here needs a postinstall script, a config change to another
74
81
  tool, or elevated permissions. If a "residoo" you found asks for any of
75
82
  those, it isn't this project.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "residoo",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Find secrets leaking through your AI coding agent's session history. Zero network calls in the scan path, zero dependencies.",
5
5
  "license": "MIT",
6
6
  "author": "CloudRoam (https://cloudroam.io)",