The key stays home.
The model gets
sk_live_51H…4Q2 never leaves your machine.
Prefer to run it yourself? See the two commands
Masked on the way out. Restored on your side.
Four checkpoints sit between your machine and the model. Each one is a plain script that runs locally, so the same input always gets the same result and the model can't talk its way past it.
Your laptop is the boundary. ZeroH runs on it as a local proxy plus Claude Code hooks. Real values stay on the laptop; only tokens cross the internet to the model provider.
- You type “Refund order 1182 for alice@acme.com”. The local proxy masks it, and the model receives [EMAIL-2b8d4c].
- Claude answers with a command that uses [API_KEY-7a3f9e]. Just before it runs on your laptop, the PreToolUse hook puts the real key back, only for api.stripe.com. The real key travels to api.stripe.com, its allowed host, and the call succeeds; the same key sent to a host that isn't allowed is blocked on your laptop and never leaves it.
- The command's output, STRIPE_KEY=sk_live_51Hx…, is masked on its way back to the model (PostToolUse), so the model sees [API_KEY-7a3f9e].
- Claude's answer arrives with tokens, and your screen shows the real values (MessageDisplay).
If it would hurt to leak, it becomes a token.
Pick a kind of data. Switch between your file, what the model gets, and the token map that links them, which never leaves your machine.
About 220 provider formats from the gitleaks rule set, plus every value in your own .env and credential files, matched exactly. Publishable keys, public keys, commit hashes and UUIDs are left alone.
Most work runs on tokens. When it can't, you decide.
Your sign-up form rejects real customers. The log shows Claude only [EMAIL-3f9c21], so it can't see the apostrophe in anna.o'neil@example.co.uk. Unmask one kind of data, for a while.
It works it out at home
Claude runs code with tokens. It runs on your machine with the real values, and only the result comes back.
$ node check.mjs [EMAIL-3f9c21] → Claude gets validateEmail: rejected → you see anna.o'neil@example.co.uk
You unmask one kind of data, for a while
Claude names the kind of data and why. Claude Code asks you, not Claude, how long to show it.
Why: see why validateEmail rejects these sign-ups
└ EMAIL unmasked for 15 minutes, until 10:47 · to end it early, tell Claude or run /zeroh-disclosure:unmask revoke
- Keys are never unmasked. They are put back only inside the command that runs.
- Limits are yours. 15 minutes, an hour, or until the session ends, within the cap you set per kind. On Enterprise, your DPO sets them.
- It ends on time, with a record. Say "stop showing emails" and it ends. Each reveal goes on your receipt; what Claude already saw stays until you
/clear.
Try it in a minute
Once it's installed: read a secret file, use the key, read the receipt. No Stripe account needed.
Nothing to hand over. Nothing to trust us with.
[API_KEY-7a3f9e]Start free. Add more when you need it.
Keys are always found on your machine, on every plan.
Free
AvailableFor anyone using Claude Code who wants keys and personal data out of the chat. Runs on your machine (macOS, Windows or Linux), no account.
Install freePremium
WaitlistFor people who handle other people's data. Adds names, amounts and IDs recognised in context, your own detection rules, images and scanned PDFs, and ProofPack reports.
Join the waitlistEnterprise
For organisations. A gateway for every request, your DPO's rules, and an audit trail with reports.
Talk to ZeroHYour tools ship daily. We test the same day.
We don't promise a release never breaks anything. We promise to notice the same day and fix it.
How we test
- Releases, versions and dates are real, read from each tool's npm channel.
- Checked every day at 05:17 UTC; at most one live test run per day.
- Every Claude Code release is tested on Linux, macOS, Windows (Git Bash) and Windows (PowerShell).
- Test results shown here are illustrative until the public records start at launch.
- Codex and OpenCode releases are recorded now; their tests start when their plugins ship.
Install it, then keep working the way you do.
No account and no configuration. It runs with the local detection rules and the default policy.