DEV Community

Furkan Beydemir
Furkan Beydemir

Posted on

I scanned my own laptop for leaked secrets and found 62,311 of them

Last week I got a little paranoid about how much sensitive data my AI
coding tools were writing to disk. So I built a scanner and pointed it at
my own home directory.

Here's what it found on a completely normal workday:

$ keynv doctor

  !  zsh history                 5 likely secrets across 1 file
  !  Claude Code transcripts     62,306 likely secrets across 73 files
  ·  Cursor logs                 clean

  Total: 62,311 likely secrets across 74 files.

  Top patterns:
    aws-access-key-id       90
    openai-api-key          81
    github-pat-classic      59
    jwt                     59
    slack-webhook           45
    stripe-live-secret-key  34
    postgres-uri            515
Enter fullscreen mode Exit fullscreen mode

62,311. In plaintext. On disk. On one developer's machine.

"But I use a secrets manager"

So do I. It made zero difference here — and that's the whole point.

Vault, Doppler, 1Password, Infisical... these tools all solve one problem
extremely well: where you store a secret at rest. That machine above
would pass any of their audits clean.

But a secret's life doesn't end at storage. At some point it gets
resolved into a real value and used — and the moment it touches a
runtime text surface, storage-era tooling stops protecting it. Those
surfaces are:

  • your shell history (~/.zsh_history)
  • your terminal's stdout
  • CI logs
  • and — the big new one — your AI agent's transcript

Why AI agents made this so much worse

Claude Code stores every session as JSONL. Cursor keeps logs. These tools
faithfully record every command they run and every byte of output they
see. That's a feature — it's how they keep context.

It also means every time the agent:

  • cats a .env file
  • hits a connection error containing a postgres://user:password@host URI
  • echoes an API key into a stack trace

...that secret gets written to disk in plaintext, in a file you forgot
exists. 62,306 of my 62,311 leaks lived in exactly these transcripts.

What I built

I ended up building an open-source tool called keynv around two ideas.

1. Alias-first resolution

Instead of putting the real value anywhere, you reference an alias:

# .keynv.env  (safe to commit — it holds aliases, never values)
OPENAI_API_KEY=@demo.dev.openai-key
DATABASE_URL=@demo.prod.db-url
Enter fullscreen mode Exit fullscreen mode

Then you wrap your command:

keynv exec -- npm run dev
Enter fullscreen mode Exit fullscreen mode

keynv exec resolves each @alias to its real value inside a
privileged subprocess your AI agent's process tree can't read
, and forks
your command with the real environment. Your shell, your editor, and the
agent driving the terminal only ever see the alias literal:

your code:          keynv exec -- mysql -p@billing.prod.db_password
                                      │
                                      ▼
the AI agent sees:  "@billing.prod.db_password"   (just the alias)
the database sees:  the actual password           (decrypted out of reach)
Enter fullscreen mode Exit fullscreen mode

2. Text-surface scrubbing

For the secrets that leak the old-fashioned way (a copied error, a
cat .env you ran by hand), keynv monitors and cleans the surfaces
directly:

Command What it does
keynv doctor Read-only scan — counts likely leaks, never prints raw values
keynv scrub Atomic in-place rewrite with .bak backups
keynv shell install Regex history hook — scrubs before a command lands in history
keynv watch start chokidar daemon — scrubs live agent sessions in real time

The two layers compose: aliases stop leaks before they land, scrubbing
catches the ones that slip through.

Try it on your own machine (30 seconds, read-only)

npm install -g @keynv/cli
keynv doctor
Enter fullscreen mode Exit fullscreen mode

doctor is scan-only — it writes nothing, makes no network calls, and
match previews are capped at 3 characters so raw values never appear in
the output. I'd genuinely love to know what number you get.

The honest part

The scrubbing half has a race window: between the moment a secret hits
the disk and the moment the watcher rewrites it, it exists in plaintext.
I'm not going to pretend that's airtight — it's documented in the threat
model. That's exactly why the alias half is the primary defense (the
value never reaches the surface at all) and scrubbing is the backstop.

keynv is also explicitly not a Vault/Doppler replacement, a .env
replacement, or a secrets manager. It plugs in next to whatever you
already use. Storage is solved; runtime text-surface protection is the gap.

It's MIT licensed, fully local (nothing leaves your machine), and
self-hostable.

If you run keynv doctor, drop your number in the comments — I'm curious
how universal this is. And if you see a hole in the threat model, I want
to hear it.

Top comments (1)

Collapse
 
alexshev profile image
Alex Shev

The scary part is not only the number of leaked-looking artifacts, it is how many places modern dev workflows casually copy context into. For AI coding tools, local secret scanning should probably run before the assistant ever sees a workspace, not after the fact as cleanup.