whatileaked 0.3.0 → 0.4.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.
- package/README.md +14 -1
- package/dist/cli.js +29 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# whatileaked
|
|
2
2
|
|
|
3
|
+
[](https://github.com/selan-ai/whatileaked/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
Your coding agent saves every conversation to your disk. If you ever pasted an
|
|
4
6
|
API key into a chat, or asked the agent to read a `.env` file, that key is now
|
|
5
7
|
sitting in a log file on your laptop — and it was uploaded to Anthropic or
|
|
@@ -103,6 +105,17 @@ same credential always produces the same code, so two rows sharing a code are
|
|
|
103
105
|
one key you reused in two places, and two different codes are two different
|
|
104
106
|
keys.
|
|
105
107
|
|
|
108
|
+
### Sharing it
|
|
109
|
+
|
|
110
|
+
The last line of every scan is made only of counts — no project, path, rule or
|
|
111
|
+
fingerprint — so it is the part you can paste or screenshot anywhere:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
whatileaked: 3 credentials sent to a model provider, across 561 transcripts.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A clean scan ends the same way, with `no credentials`.
|
|
118
|
+
|
|
106
119
|
---
|
|
107
120
|
|
|
108
121
|
## Is it a real key, or just a test fixture?
|
|
@@ -193,7 +206,7 @@ npx whatileaked scan || echo "found something"
|
|
|
193
206
|
| Agent | Folder |
|
|
194
207
|
| --- | --- |
|
|
195
208
|
| Claude Code | `~/.claude/projects/` · `~/.claude/CLAUDE.md` |
|
|
196
|
-
| Codex | `~/.codex/sessions/` · `~/.codex/AGENTS.md` |
|
|
209
|
+
| Codex | `~/.codex/sessions/` · `~/.codex/archived_sessions/` · `~/.codex/AGENTS.md` |
|
|
197
210
|
| Cursor | `~/.cursor/projects/*/agent-transcripts/` |
|
|
198
211
|
|
|
199
212
|
Cursor keeps its older Ask-mode chats in SQLite rather than jsonl, and those are
|
package/dist/cli.js
CHANGED
|
@@ -162,6 +162,7 @@ var TerminalReporter = class {
|
|
|
162
162
|
this.#write(green("No credentials found."));
|
|
163
163
|
this.#write("");
|
|
164
164
|
this.#write(dim(DISCLOSURE));
|
|
165
|
+
this.#share(sent, stats);
|
|
165
166
|
return;
|
|
166
167
|
}
|
|
167
168
|
for (const total of totals) {
|
|
@@ -196,6 +197,22 @@ var TerminalReporter = class {
|
|
|
196
197
|
this.#write(dim("Some findings will be test fixtures \u2014 open the file to tell."));
|
|
197
198
|
this.#write("");
|
|
198
199
|
this.#write(dim(DISCLOSURE));
|
|
200
|
+
this.#share(sent, stats);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* The one line meant to be pasted somewhere public. Everything above it names
|
|
204
|
+
* projects, paths and fingerprints, so nobody shares it; this is counts only,
|
|
205
|
+
* and stays that way. It is last so a screenshot can crop to it, unstyled so
|
|
206
|
+
* a copy carries nothing but the words, and it repeats the headline's
|
|
207
|
+
* transmitted-only count for the same reason the headline keeps memory files
|
|
208
|
+
* out of it.
|
|
209
|
+
*/
|
|
210
|
+
#share(sent, stats) {
|
|
211
|
+
const credentials = sent === 0 ? "no credentials" : plural(sent, "credential");
|
|
212
|
+
this.#write("");
|
|
213
|
+
this.#write(
|
|
214
|
+
`whatileaked: ${credentials} sent to a model provider, across ${plural(stats.transcripts, "transcript")}.`
|
|
215
|
+
);
|
|
199
216
|
}
|
|
200
217
|
};
|
|
201
218
|
function count(value) {
|
|
@@ -2606,17 +2623,18 @@ var CodexSource = class {
|
|
|
2606
2623
|
if (instructions !== null) {
|
|
2607
2624
|
yield { source: this.name, kind: FileKind.memory, path: instructions, project: this.name };
|
|
2608
2625
|
}
|
|
2609
|
-
const root
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2626
|
+
for (const root of ["sessions", "archived_sessions"]) {
|
|
2627
|
+
for (const dir of await walkDirectories(join3(this.#home, ".codex", root))) {
|
|
2628
|
+
for (const file of await listFiles(dir, FileExtension.jsonl)) {
|
|
2629
|
+
const path = join3(dir, file);
|
|
2630
|
+
const cwd = await firstCwd2(path);
|
|
2631
|
+
yield {
|
|
2632
|
+
source: this.name,
|
|
2633
|
+
kind: FileKind.transcript,
|
|
2634
|
+
path,
|
|
2635
|
+
project: cwd === null ? basename2(dir) : basename2(cwd)
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2620
2638
|
}
|
|
2621
2639
|
}
|
|
2622
2640
|
}
|