You removed the secret from your code. You pushed the fix. You're safe.
You're not.
The key still lives in your git history — commit a3f92e1, six months back — and public scrapers and sweeper bots read that history every day. Roughly 40% of the $16.7B lost to crypto hacks comes from compromised private keys (DeFiLlama via CoinDesk), and GitGuardian's research shows most leaked secrets stay valid for years after disclosure.
I built a tool for exactly this problem. It's called drainscan — open source, MIT — and this post shows it catching a "deleted" secret in under two seconds.
The trap: working-tree scanners miss history
Here's the classic incident, replayed. Someone commits a real key:
# config.py (commit 1)
DATABASE_URL=postgres://localhost/dev
PRIVATE_KEY=0x8f2c...d4c0
Then someone notices and removes it:
# config.py (commit 2)
DATABASE_URL=postgres://localhost/dev
Scan the current tree with anything and you get a green light. The key is gone. Except it isn't:
$ git show HEAD~1:config.py | grep PRIVATE_KEY
PRIVATE_KEY=0x8f2c...d4c0 # still right there
What drainscan does differently
drainscan detects EVM private keys, Solana keys (base58 and Phantom-style JSON arrays) and BIP-39 mnemonics — then does two things generic scanners can't:
- Derives the address offline. Your key material is never transmitted anywhere; you learn which wallet leaked without exposing it further.
-
Checks balances read-only (
--live). A leaked key with 0 balance is noise; one holding funds is an emergency. drainscan tells you which.
It also kills false positives with context scoring: transaction hashes are 64 hex chars too, so tx_hash = 0x9fc7... gets downgraded to low confidence, while PRIVATE_KEY= context scores high. BIP-39 checksum validation means random English sentences never trigger alerts.
Demo: catch the deleted key
Working-tree scan on the repo where we just "fixed" the leak:
$ drainscan scan . --min-confidence high
No key material found. You're clean (at detected patterns).
Now the deep scan (Pro feature):
$ drainscan history --max-commits 10
Deep-scanning git history (up to 10 commits)...
1 finding(s):
[!!] evm_key - config.py @ 2ad95e6c:0 (high)
secret: a67296...141d (redacted)
address (ethereum): 0x8a5be301cb283f2e32496c4953b2ceab17b59867
exit code: 1
That address matches the planted key exactly. Exit code 1 means CI can fail the build — wire it into GitHub Actions and no PR that reintroduces key material can merge.
Free vs Pro
Everything above runs free forever: working-tree scanning, offline derivation, balance checks, confidence scoring, CI exit codes, pre-commit hooks.
Pro ($99 one-time during intro) adds what teams need: full-history deep scans at any depth, SARIF reports that surface findings directly in GitHub code scanning UIs, and standalone HTML reports for security review meetings.
Licenses are Ed25519-signed files verified locally — no account, no telemetry, no phone-home.
Try it
pip install git+https://github.com/ezequiellich44-cmd/drainscan.git
drainscan scan .
Run it against your oldest repo. If you've ever pasted a private key into config while debugging, you probably already know what it will find — better you than a sweeper bot.
If drainscan finds a funded key: move the funds to a fresh key immediately and treat the old one as burned. Rotation is the only fix.
Top comments (0)