Prevent leaks with AI Hooks
AI Hooks make ggshield part of the AI coding tools your developers already use. When a prompt or a tool call contains a secret, ggshield blocks the action before it reaches the model and tells the developer or the agent what to remove. When a secret only appears in a tool's output, which a shell command or an MCP response can produce unpredictably, the action has already run. Some assistants let ggshield withhold that output so the model never sees it; on the rest, ggshield raises a desktop notification so the developer knows to rotate. See what each assistant supports.
Why AI Hooks matter on developer endpoints
Endpoint scanning inventories the credentials already sitting on a machine. AI Hooks stop new ones from leaving it.
Developers using AI coding tools leak secrets at roughly twice the baseline rate. An agent asked to debug a failing deployment reads the .env file or ~/.aws/credentials and passes the contents to a model provider. There is no commit, no push, and no pull request, so none of the checkpoints that protect your repositories and CI ever fire.
Hooks act at the moment of the interaction, which gives you a few things:
- Prevention rather than cleanup. A secret caught in a prompt or a tool call never reaches a third party, so there is no rotation to schedule and no model provider to ask about retention. The same holds for a tool's output on the assistants that let
ggshieldwithhold it. - A fix the developer can act on. Every block names the detected secret and what to remove, so the developer or the agent can correct the content and retry immediately.
- No extra agent to deploy. Hooks reuse the
ggshieldbinary you already install for scanning. They run only when the AI tool calls them, so there is no resident process on the machine.
What hooks scan
ggshield registers on three stages of an AI interaction:
- Prompt submission: the prompt is scanned before it reaches the model, and blocked if it contains a secret.
- Pre-tool use: file reads, shell commands, and MCP calls are scanned before the agent runs them, and blocked if they contain a secret.
- Post-tool use: the tool has already run, so what
ggshieldcan do depends on the assistant. Where the assistant allows it, the output is withheld and the model never sees the secret. Everywhere else the developer gets a desktop notification and the secret should be treated as exposed.
Detection uses the same engine as every other ggshield scan, covering 600+ types of secrets.
What each assistant supports
The first two stages behave the same nearly everywhere: a secret in a prompt, in a command, or in a file about to be read is blocked before it reaches the model. The third stage is where assistants differ, because replacing a tool's output is something the assistant has to offer and most do not.
| Assistant | Minimum ggshield | Secret in a prompt | Secret in a command or file read | Secret in a tool output |
|---|---|---|---|---|
| Claude Code | 1.49.0 | Blocked | Blocked | Withheld for shell commands and file reads, notification only for MCP and other tools |
| Cursor | 1.49.0, 1.55.0 on Windows | Blocked | Blocked | Notification only |
| VS Code | 1.51.0 | Blocked | Blocked | Notification only |
| Copilot CLI | 1.52.0 | Blocked | Blocked | Notification only |
| Codex | 1.53.0 | Blocked | Blocked | Withheld for every tool |
| Mistral Vibe | 1.54.0, with Vibe 2.21 or later | Blocked | Blocked | Withheld for every tool |
| Junie CLI | 1.55.0 | Blocked | Blocked | Not available: Junie runs no post-tool hook |
| Kiro CLI | 1.55.0 | Blocked | Blocked | Notification only |
| Kiro IDE | 1.55.0 | Detected, not blocked | Blocked | Notification only |
Where the output is withheld, the assistant reads the ggshield message in place of the tool's output, so the secret never reaches the model provider and there is no need to rotate it. The message suggests how to keep the secret out of the next output instead, such as moving it to a secrets manager or not sharing the file with the agent. The command itself still ran, so any effect it had on your systems, such as an API call or an access log entry, still happened. Withholding requires ggshield 1.55.0 or later.
What stays on disk depends on the assistant. Claude Code writes the ggshield message to its session transcript in place of the output. Codex and Mistral Vibe still write the raw output to their own session files, the rollout files under ~/.codex/sessions/ and the Vibe session log, where no hook can reach it. That copy is local, so on its own it is no reason to rotate, but delete the session file if you don't want the secret kept there in plain text.
Where only a notification is possible, the assistant has already been given the output. Treat the secret as exposed and rotate it.
Three assistants need a note:
- Junie is covered as the Junie CLI only. Junie inside a JetBrains IDE runs over ACP, which invokes no hooks, so nothing is scanned there.
- Kiro CLI reads the hook configuration only in v3 mode. Start it with
kiro-cli --v3; other sessions take their hooks from the agent configuration instead and the installed hook does not apply. - Kiro IDE cannot block a prompt.
ggshielddetects the secret, but the prompt still reaches the model. Treat the secret as exposed and rotate it.
For per-tool setup, what the blocking message looks like to a developer, and how to handle false positives, see Secret scanning for AI coding tools.
What a hook sends
Detection happens on GitGuardian's side, so the content of the interaction is scanned by the API, the same way ggshield scans a commit or a push. Hooks also report each MCP tool call, with the tool and server name and the arguments the agent passed. That is what fills your MCP activity view and what carries the allow or deny decision back to the tool.
Machine scans work the other way around and keep detection on the endpoint. For the full breakdown of both, see Data handling & privacy.
Deploy AI Hooks across your fleet
Hooks protect a machine only once they are configured on it, and asking each developer to opt in leaves gaps exactly where you need coverage. Push them through your MDM instead, alongside the rest of Endpoint Protection.
Scanning needs a token every time a hook fires, and because hooks run in the developer's own session rather than in your MDM job, that token has to be the developer's. Inject an admin service account token at runtime to install the hooks, then log the developer in so the hook scans under their membership: see Step 4 and Step 5.
To set up a single machine, run one command as the logged-in user:
ggshield machine setup
machine setup configures the hook for every AI coding assistant it detects, and skips the ones that are not installed. It also installs the git pre-commit and pre-push hooks and plants a honeytoken, so add --no-git-hooks or --no-honeytokens if you want AI Hooks alone. To pick or exclude specific assistants, use --agent or --exclude-agent with any of claude-code, codex, copilot, cursor, junie, kiro, vibe, and vscode.
machine setup requires ggshield 1.53.0 or later. The minimum version for each assistant's hook is listed in What each assistant supports. On earlier versions, install one assistant at a time with ggshield install -t <assistant> -m global, which still works but is deprecated.
Verify that hooks are active
On a sample machine, as the logged-in user, run:
ggshield machine doctor
machine doctor is read-only and reports, for every assistant it finds on the machine, whether the hook is installed. It also checks that the token reaches GitGuardian and carries the scopes your protections need, and it exits non-zero if any check fails, so you can run it as an MDM audit script. Each failed check prints its own fix.
Both halves of that check matter. Because hooks fail open, a machine with hooks installed but no working credentials looks the same to a developer as a machine with nothing to block, apart from the warning that the content was not scanned.
To confirm end to end, paste a test credential into a prompt and check that the tool displays the ggshield blocking message.
Roll back
Disabling the MDM setup job stops new machines from receiving hooks, but leaves the configurations already on disk in place. To remove them, delete the ggshield entries from the tool's hook configuration:
| Tool | Hook configuration |
|---|---|
| Claude Code | ~/.claude/settings.json |
| Cursor | ~/.cursor/hooks.json |
| Codex | ~/.codex/hooks.json |
| Copilot CLI and VS Code | ~/.copilot/hooks/hooks.json |
| Mistral Vibe | ~/.vibe/hooks.toml |
| Kiro | ~/.kiro/hooks/ggshield.json |
| Junie | ~/.junie/config.json |