Local, loopback-only gateway for AI coding tools
Redact secrets and PII before they reach the model
Tokenhush sits between your AI coding tool and the vendor API. It replaces detected secrets in the outbound request body with session-scoped placeholders, forwards the cleaned request, and restores the originals in the response — so your tool still gets the real values back.
Open source under Apache-2.0. No MITM, no root certificate; the secret-to-placeholder mapping lives in memory only.
- 5
- detectors on by default
- 14
- tools with a ready-to-paste setup snippet
- 7
- CLI commands, seven and no more
- Apache-2.0
- license
Each figure is verifiable against the public core; every number is mapped to its source in the site's content-source map.
Three paths into the gateway
Install the binary, connect one tool, and watch the redaction log — each step has a matching guide.
- Install
Install the binary
Homebrew on macOS, a one-line installer on Linux and Windows. The Linux and Windows scripts verify the archive checksum before installing, and none of them need admin rights.
Read the install guide - Connect
Point a tool at the gateway
Any client that accepts a custom base URL works — 14 tools ship with a ready-to-paste snippet. Start the gateway with tokenhush run; it listens on 127.0.0.1:8787.
See per-tool setup - Verify
Watch it work
Every redaction prints one masked line to the gateway log, every restore prints a count, and every local refusal prints its reason. No dashboard required.
Follow the verification guide
- Your tool sends
OPENAI_API_KEY=<real key>- The model receives
OPENAI_API_KEY=__PII_api_key_ae9c0b46a8f3__- Your tool gets back
OPENAI_API_KEY=<real key>
Placeholder form__PII_<type>_<digest>__
What the gateway does
One checkpoint in front of the tool: read each request, replace anything that looks like a secret, forward the cleaned body.
Every nested field is walked
The whole outbound JSON body is read, so secrets buried in nested objects and arrays are seen, not just top-level fields. Responses, SSE streams included, are buffered whole before anything is committed.
Six built-in detectors, five on by default
prefix, jwt, pem, luhn, and email run by default. The sixth, entropy, is opt-in per workload because its false positives on real agent traffic broke function calling.
Reversible, session-scoped placeholders
A match becomes a placeholder such as __PII_api_key_ae9c0b46a8f3__. The secret-to-placeholder mapping is kept in memory for the session only; restarting the gateway drops it.
Loopback only, with checks
Binds 127.0.0.1, plus [::1] when the host has an IPv6 loopback. The Host allowlist is always enforced, Origin is checked for browser-style requests, and the control API sits behind a per-run token stored 0600.
Signed rule packs, with a non-weakening floor
tokenhush rules sync verifies an Ed25519-signed pack’s signature, freshness, and serial before use. The floor refuses a pack that disables a built-in detector, drops a required category, or carries an allow action.
Small, portable, extensible
Pure Go, built with CGO_ENABLED=0. Extension is compile-time by design: built-ins, signed packs, and third-party rules all enter the same registry through one Rule contract.
What Tokenhush does not do
The boundaries are part of the design, and each one is written down rather than discovered later.
No MITM, no root certificate
Tokenhush never terminates TLS. That is also why Cursor agent traffic, the ChatGPT and Claude desktop apps, and browser web UIs are not covered: they do not honour a configurable base URL.
The response path does not redact
Response-scoped rules can allow, warn, or block only. A response over the buffer cap is a 502 and one past the timeout is a 504, both before any byte is committed.
Encoded secrets are not caught
A secret that is base64-, hex-, or URL-encoded before it leaves is not detected. A non-identity Content-Encoding is refused with 415 rather than decoded.
JSON object keys are not scanned
Only values are walked, so a secret used as an object key is not caught.
Extensions are compile-time only
There is no runtime plugin loading, no allowlist-mutation endpoint, and no built-in service command — pair the gateway with your OS service manager if you want it to start at login.
The documentation records the full boundary list and the residual risks that come with it.
Six detectors, five on by default
Deterministic detectors run on the outbound request body; each match becomes a session placeholder before the request is forwarded.
| Detector | What it catches | Default |
|---|---|---|
| prefix | Vendor key shapes — sk-, AKIA, ghp_, glpat-, xox*, AIza, npm_ | On |
| jwt | JSON Web Tokens | On |
| pem | PEM private-key headers (-----BEGIN … PRIVATE KEY-----) | On |
| luhn | Card numbers that pass the Luhn check | On |
| Addresses whose domain ends at a known public suffix (.com, .co.uk, …) | On | |
| entropy | High-entropy strings — off by default because its false positives on real agent traffic broke function calling | Off (opt-in) |
Fourteen tools, one snippet each
Any client that accepts a custom base URL works. These 14 ship with a ready-to-paste snippet from tokenhush env; Anthropic-style clients take the bare origin, OpenAI-compatible clients take /v1.
- Claude CodeANTHROPIC_BASE_URL
- Codex CLI~/.codex/config.toml
- AiderOPENAI_API_BASE / ANTHROPIC_API_BASE
- ClineOpenAI Compatible base URL
- Roo CodeOpenAI Compatible base URL
- opencodeopencode.json
- Qwen CodeOPENAI_BASE_URL / ANTHROPIC_BASE_URL
- Charm Crushcrush.json
- Zedsettings.json
- Continue.dev~/.continue/config.yaml
- Open WebUIOPENAI_API_BASE_URL
- GooseOPENAI_HOST + OPENAI_BASE_PATH
- OpenHandsLLM_BASE_URL
- Kilo CodeOpenAI Compatible base URL
Using something else? Point its OpenAI-compatible base URL at http://127.0.0.1:8787/v1, or its Anthropic base URL at http://127.0.0.1:8787.
How Tokenhush compares
Four paths people take, and what each one trades away.
| Approach | What it gives you | What it does not |
|---|---|---|
| Opt-outs and .gitignore | No extra software: keep secrets out of the files you remember to exclude, and switch off provider features per tool. | You have to get every pattern right and keep it right. One forgotten .env still leaves the machine, and there is no undo after a request is sent. |
| Turning off the features that send too much | Fewer bytes leave, sometimes a lot fewer. | You lose capability, the setting can drift or be reset by an update, and it does nothing about secrets that reach the request anyway. |
| A local MITM proxy with a root certificate | Can inspect and rewrite traffic from any client on the machine, including ones with no base-URL setting. | It terminates TLS, so you install a root certificate and add a permanently trusted party to your machine. |
| Tokenhush | A loopback gateway your tool points at: reversible placeholders in the request body, restored in the response. No TLS termination, no root certificate, and the mapping lives in memory only. | It covers tools you can point at a base URL (14 helpers ship). It does not redact the response path, catch encoded secrets, or cover clients that ignore base URLs. |
Loopback only, no root certificate
Tokenhush binds 127.0.0.1 — plus [::1] where the host has an IPv6 loopback — and checks the Host allowlist on every request. It never terminates TLS, so there is no root certificate and no system-wide interception.
- Nothing to trust system-wideNo root certificate, no TLS termination, and no second endpoint: the control surface is exactly GET /status behind a per-run token.
- Two base-URL formsAnthropic-style clients take the bare origin; OpenAI-compatible clients take /v1.
# Anthropic-style clients
http://127.0.0.1:8787
# OpenAI-compatible clients
http://127.0.0.1:8787/v1It fails closed, not open
A detector failure refuses the request rather than forwarding it unredacted. Encoding, size, and timing limits each have a defined refusal instead of a silent partial send.
- No partial forwardsA body over the memory guard is refused before any upstream dial, and a response over the buffer cap is a 502 before commit.
- Encoding is not guessedA non-identity Content-Encoding is rejected with 415 rather than decoded for detection.
403 body_too_large
415 unsupported Content-Encoding
502 response over the buffer cap
504 response past the timeoutExtend it at compile time
Built-in detectors, signed rule packs, and your own Go package all enter the same registry through the Rule contract in pkg/filter, and evaluate in one deterministic order.
- Add, never weakenA signed pack may add detections and extend the built-in email suffix set, but the floor refuses anything that would weaken a built-in.
- One registryBuilt-ins, packs, and third-party rules share one registry and one evaluation order.
built-ins → one registry
signed rule packs → verified, non-weakening floor
compile-time plugins → your own Go packageWhat can leave your machine
The only vendor-bound traffic Tokenhush itself can send is two switchable categories — update check and rule sync. Each short-circuits before any network call when its switch is set.
Update check
Runs only on
tokenhush update. Switch it off withTOKENHUSH_NO_UPDATE_CHECK=1.Rule sync
Runs only on
tokenhush rules sync. Switch it off withTOKENHUSH_NO_RULE_SYNC=1.
See the full egress disclosure — hosts, fields, retention, and switches.
Open source
Start the gateway, point your tool at it
Apache-2.0 licensed and built in public. Install the binary, run tokenhush run, and set one base URL — the setup guide walks through each of the 14 tools.
- Apache-2.0
- No root certificate