Your coding agent saves every conversation to your disk. If you ever pasted an
API key into a chat, or asked the agent to read a .env file, that key is now
sitting in a log file on your laptop — and it was uploaded to Anthropic,
OpenAI or Google the moment you sent the message.
Secret scanners point at repositories and CI. You can aim one at ~/.claude by
hand, but nobody does — it is not a repo, it is not in CI, and it does not look
like a place credentials live. It is.
This tool looks there and tells you what it finds.
You don't. Open a terminal and run:
npx whatileaked scannpx comes with Node.js. It downloads the tool, runs it once, and does not
install anything permanently.
No Node.js? Check with node --version. If that errors, install Node from
nodejs.org (any version 20 or newer) and try again.
If you'd rather keep it around:
npm install -g whatileaked # then just: whatileaked scanThere are two commands and no options.
npx whatileaked scan # look, and tell you. Changes nothing.
npx whatileaked wipe # remove what it found. Asks before touching anything.Running npx whatileaked with no command just lists them.
A scan takes about 20 seconds for a year of history. It reads files, and that is all — no network connection is made at any point.
scanned 561 transcripts · 197,016 messages · 3 memory files
No credentials found.
Nothing to do. This is the good outcome.
scanned 561 transcripts · 196,986 messages · 3 memory files
* aws-access-token 2 secrets
f0b93847 billing-api sent 25 times
const SECOND_AWS_KEY = '***
~/.claude/projects/-Users-you-code-billing-api/965db026.jsonl
2bcf6de0 deploy-tool sent once
AWS_ACCESS_KEY_ID=***
~/.claude/projects/-Users-you-code-deploy-tool/c8dd5ea8.jsonl
* github-pat 1 secret
c40a1f77 auth-service sent 4 times
gh auth login --with-token ***
~/.claude/projects/-Users-you-code-auth-service/1254ccd7.jsonl
3 credentials sent to a model provider.
Every line, explained:
| Part | Means |
|---|---|
* aws-access-token |
The kind of credential. These names come from gitleaks, so you can search any of them. |
2 secrets |
How many different credentials of that kind. |
f0b93847 |
A fingerprint — not the secret. See below. |
billing-api |
The project folder you were working in at the time. |
sent 25 times |
How many messages carried it. One paste gets re-sent with every later message in the conversation. |
const SECOND_AWS_KEY = '*** |
The text right before the secret, with the secret blanked out. This is how you judge it. |
~/.claude/projects/… |
The file to open if you want the whole story. |
What is a fingerprint? A short one-way hash of the secret. The tool never prints the credential itself — not even the first few characters — because you might paste this output somewhere public. The fingerprint is still useful: the same credential always produces the same code, so two rows sharing a code are one key you reused in two places, and two different codes are two different keys.
The last line of every scan is made only of counts — no project, path, rule or fingerprint — so it is the part you can paste or screenshot anywhere:
whatileaked: 3 credentials sent to a model provider, across 561 transcripts.
A clean scan ends the same way, with no credentials. If some of it could not
be scanned, the line says how much, still in counts only — (7 messages and 1 file not scanned) — so a pasted partial scan never reads as a clean one.
Some findings will be fake. A credential-shaped string in a test file is still credential-shaped, and no scanner can tell them apart. You can:
- Read the masked line.
const TEST_KEY = ***is a fixture.AWS_ACCESS_KEY_ID=***probably is not. - Look for a repeated fingerprint. The same code under several different projects is a credential you genuinely reused.
- Open the file. The path is printed for exactly this.
Well-known example keys are already filtered out — AWS's own published
AKIAIOSFODNN7EXAMPLE is never reported.
Rotate the key first. Log into AWS, GitHub, wherever it came from, and issue a new one. This matters more than anything below: the old key has already left your machine, and deleting your local copy does not call it back.
Then, if you want, clean your disk:
npx whatileaked wipeIt shows you every file it would touch, then stops and waits:
replacing credentials in your local transcripts with a placeholder
3 secrets across 2 files
* billing-api 2 secrets in 2 messages
~/.claude/projects/-Users-you-code-billing-api/965db026.jsonl
* auth-service 1 secret in 1 message
~/.claude/projects/-Users-you-code-auth-service/1254ccd7.jsonl
Every secret above will be replaced with a placeholder.
This rewrites the files and cannot be undone.
It does not un-send anything — all of these already reached a model
provider. Rotate them whether or not you wipe.
Type wipe to rewrite these files, or anything else to stop:
You must type the full word wipe. Pressing y does nothing, and a scripted
run cannot answer at all — yes | whatileaked wipe changes no files.
Each secret becomes [REDACTED BY whatileaked: aws-access-token]. Only the
lines containing a secret change, the rest of the file is untouched, and the
file stays valid so your agent can still read its own history.
| What you see | What it means | What to do |
|---|---|---|
command not found: npx |
Node.js isn't installed. | Install it from nodejs.org. |
unknown command "..." — expected "scan" or "wipe" |
A typo. | Check the spelling. |
Nothing was scanned, so this is not a clean result. |
It found no agent history where it looks. | Your agent may not be supported yet, or keeps its history somewhere else. See Where it looks. |
Found … but did not scan it: … |
That file was found but could not be read, for the reason given — an opencode or Kilo Code database on Node older than 22.13, for one. | Use Node 22.13 or newer for opencode and Kilo Code. For any other reason, please open an issue. |
N messages could not be scanned |
Some entries were unreadable and were skipped. | The count is shown so a partial scan never looks like a clean one. Please open an issue. |
Not confirmed. Nothing was changed. |
wipe didn't get the word wipe. |
Expected. Nothing was touched. |
| It seems stuck | A big history takes ~20 seconds. | Give it a minute before worrying. |
Exit codes, if you want to script it:
| Code | Meaning |
|---|---|
0 |
Nothing found |
1 |
Credentials found |
2 |
An error |
npx whatileaked scan || echo "found something"| Agent | Folder |
|---|---|
| Claude Code | ~/.claude/projects/ · ~/.claude/history.jsonl · ~/.claude/paste-cache/ · ~/.claude/CLAUDE.md |
| Codex | ~/.codex/sessions/ · ~/.codex/archived_sessions/ · ~/.codex/history.jsonl · ~/.codex/AGENTS.md · ~/.codex/AGENTS.override.md |
| Cursor | ~/.cursor/projects/*/agent-transcripts/ |
| opencode | ~/.local/share/opencode/opencode.db |
| Kilo Code | ~/.local/share/kilo/kilo.db |
| Gemini CLI | ~/.gemini/tmp/*/chats/ · ~/.gemini/tmp/*/logs.json · ~/.gemini/tmp/*/checkpoint-*.json · ~/.gemini/tmp/*/memory/ · ~/.gemini/GEMINI.md |
opencode and Kilo Code keep their sessions in a SQLite database. Reading it needs Node's
built-in node:sqlite, which loads without a flag from Node 22.13. On an older
Node the scan still finds the file and says, in one line, that it was not
scanned, so a skipped database never looks clean. Only the message and part tables are
read, and wipe does not rewrite the database: delete those sessions in
the agent, and rotate.
Cursor keeps its older Ask-mode chats in SQLite as well, and those are not scanned yet. Agent transcripts are covered; Ask history is not.
Claude Code transcripts it set aside (*.jsonl.superseded-*) are scanned too.
If you moved Claude Code's folder with CLAUDE_CONFIG_DIR, Codex's with
CODEX_HOME, Gemini CLI's with GEMINI_CLI_HOME, or opencode's and Kilo
Code's with XDG_DATA_HOME, the folder it names is scanned as well as the default one,
which still holds every session from before the move. A database named by
OPENCODE_DB or KILO_DB is scanned too.
Transcripts record credentials that were already sent. So does prompt history,
which keeps every prompt you typed and every long paste after the session itself
has been cleaned up. Instruction and memory files are worse: they are read again
at the start of the next session, so a credential in one keeps leaking until the
file is edited. All of them are scanned, and wipe rewrites all of them.
Nowhere else. It does not read your repos, your shell history, or your environment — beyond the variables above, to know where to look. Adding support for another agent is one small file — pull requests welcome.
- Print a secret. Findings carry a rule name and a fingerprint. No type in this codebase has a field that can hold a credential value.
- Make a network request. Not for results, not to check for updates. Nothing leaves your machine, ever.
- Write anything — unless you run
wipeand type the word. - Pull in dependencies. Installing it adds exactly one package: this one.
Built by Selan. Selan sells a proxy that redacts these before they leave your machine, so we have an obvious interest in you finding a big number here.
The scanner is a few hundred lines with no dependencies. Read
src/scan/scanner.ts and check for yourself.
Node 24+ to develop (tests read the TypeScript sources directly). The published build is plain JavaScript and runs on Node 20+.
pnpm install
pnpm test
pnpm typecheck
pnpm lintDetection rules come from gitleaks,
used unmodified; pnpm gen:secret-rules regenerates them from upstream.
docs/design.md covers how the scanner works and why it is built this way.
MIT. gitleaks rule definitions are MIT too.