pip/pipxinstalls now ship the native Rustggshieldon common platforms
(Linux x86-64/aarch64 for glibc and musl, macOS universal2, Windows x86-64); the Python implementation is installed
alongside asggshield-py. Platforms without a native wheel fall back to the
pure-Python wheel, whereggshieldis the Python entry point — as does
Homebrew, which builds from the source distribution.
Added
-
Add secret-scanning hook support for Mistral Vibe 2.21 and later. Global and
project installation preserves existinghooks.tomlcontent and configures
Vibe'spre_toolandpost_toolevents. -
A native
ggshield-hookbinary implementsggshield secret scan ai-hook,
removing the interpreter startup cost the hook paid twice per tool call. It
resolves the instance's scan limits from the same places ggshield does
(GG_MAX_DOC_SIZE/GG_MAX_DOCS, the on-disk auth-check cache, then
/v1/metadata), so a document or a batch the instance would reject is split or
skipped instead of failing the scan. It caches what it learns from
/v1/metadatafor five minutes, so a hook path where only the native binary
runs does not pay that round trip on every scan. -
The native hook now honours the
GITGUARDIAN_INSTANCE,GITGUARDIAN_API_URL
andGITGUARDIAN_API_KEYsettings a.envfile provides, instead of declining
to scan when it found one. It reads the file from the same places ggshield does
(GITGUARDIAN_DOTENV_PATH, then the working directory, then the repository
root), and gives it the same precedence: a value in the.envoverrides the
same variable already exported in the environment. A self-hosted instance
configured through a.envis therefore scanned against, rather than left
unscanned. Two caveats: an unbraced$in a value is expanded as a variable
reference (soGITGUARDIAN_API_KEY=abc$defresolves toabc— quote it as
'abc$def'to keep the$), and aGITGUARDIAN_*line the parser rejects
still leaves the action unscanned, with a message naming the variable. -
AI discovery now reports, per agent, the email of the assistant subscription that agent is signed into, so a personal
subscription can be told apart from a company one. Read locally from Claude Code, Codex and Cursor. Mistral Vibe and
VSCode keep no account on disk and report nothing. -
GGSHIELD_NO_NOTIFICATIONsuppresses the AI hook's desktop notification. The
secret is still detected and the tool call still blocked; only the banner is
withheld.
Changed
-
Release binaries are now built with Python 3.14 instead of 3.10, ahead of Python 3.10's
end-of-life. This also updates the SQLite bundled in the released binaries, fixing
CVE-2025-6965andCVE-2025-7709. -
AI hooks no longer call the API twice for the same document. An unambiguously clean
scan result is cached locally for 15 minutes, keyed on the exact document sent and on
the instance and token it was sent with, so a file read costs one API round trip
instead of two (PreToolUseandPostToolUsescan the same file). -
ggshieldstarts faster: each command now imports only the modules it needs, and
plugin discovery runs only when a plugin command is actually resolved. This speeds
up every invocation, in particular the ones that run automatically on every git
commit (secret scan pre-commit) and on every AI agent tool call
(secret scan ai-hook). -
ggshield secret scan ai-hookis now much faster on MCP tool calls: the local
discovery walk is cached for an hour instead of running on every call, and the
secret scan and the MCP activity call now run concurrently instead of one after
the other. Measured against a mock API at the production p50 latency, an MCP
PreToolUseevent goes from 1183 ms to 387 ms (p50). Other events are
unaffected. As a consequence, an MCP tool call is now reported to GitGuardian
even when the secret scan blocks it. -
AI hooks now scan all the payloads of an event in a single API call instead of one
call each. A prompt mentioning three files used to cost four round trips; measured
against a mock API at the production p50 latency, such aUserPromptSubmitgoes from
1561 ms to 395 ms (p50). Single-payload events are unchanged. -
In the standalone packages (
.pkg,.deb,.rpm,.msi, Chocolatey, archives),ggshield
is now a small native dispatcher: it runsggshield secret scan ai-hookand hands every other
command to the bundled Python implementation. There is still a singleggshieldcommand, and
every command behaves as before. -
AI hooks now resolve the file paths of
Readtool calls and prompt@-mentions to an
absolute path against the event's working directory. A file mentioned in a prompt and the
same file later read by a tool now share one verdict-cache key, so it is scanned once
instead of twice. As a result, the file path reported in block messages (and sent for
scanning) is now absolute for prompt-mentioned files. -
The native hook accepts a
.gitguardian.yamlkey spelled with-or with_,
but no longer resolves a config that sets the same key in both spellings the
way the Python implementation does: the last spelling in the file wins. Using
one spelling per key, which every documented example does, is unaffected. -
When the AI hook blocks, its message now shows the
secret.ignored_matches
entry that would silence it, one line per detected secret. The message censors
every match, so the entry could not previously be written by hand from what it
showed. The value shown is the ignore sha, a digest rather than the secret,
and is the same oneggshield secret ignore --last-foundwrites. -
ggshield plugin installandggshield plugin updateno longer send an
installation report to the GitGuardian instance. The endpoint it targeted was
never implemented, so the call always failed and was silently discarded. -
The GitGuardian logo shipped with ggshield is the refreshed one: the Chocolatey
package icon uses the solid black mark, and the macOS desktop notification icon
uses the app icon on its own dark ground. -
ggshield now requires
py-gitguardian1.34.0, which carries the
AgentInfo.subscription_emailfield the AI discovery report sends.
Fixed
-
On macOS,
ggshieldno longer triggers the Xcode Command Line Tools install prompt
when the tools are not installed. -
On macOS,
ggshieldno longer pops a "Keychain Not Found" dialog when checking
whether the keyring is usable. The check now only reads from the credential
store instead of writing a probe entry, which also stops it from silently
falling back to file-based token storage on machines where the keychain can be
read but not written. -
ggshield secret scan ai-hookno longer skips the scan when a Bash command starting with
catorGet-Contentis not a plain file read (a heredoc, a redirection...).
Such commands are now always scanned as text. -
ggshield secret scan ai-hooknow scans only the lines an agent actually reads, instead of
the whole file. A file over the API's 1 MiB document limit was skipped outright — allowed
without being scanned at all — even when the agent only read a few hundred lines of it;
that slice now scans normally. Ranges are read from Claude Code (offset/limit) and
VS Code (startLine/endLine); a read without a range still scans the whole file. -
The AI discovery is now submitted to GitGuardian only when the local AI/MCP
configuration actually changed, as it was always meant to be. A type mismatch
between a freshly discovered MCP configuration and one read back from the local
cache made the comparison always report a change, so every MCP tool call
uploaded a full discovery payload. -
When a secret is found in a file mentioned in a prompt (
@path), AI hooks now name
that file in the block message instead of reporting it as a secret "in your prompt".
The previous wording pointed at the wrong content and asked the user to edit a prompt
that did not contain the secret. -
On macOS, the token stored by
ggshield auth loginis now created with a
Keychain ACL trusting every ggshield binary, so the native hook can read it
without prompting. Previously only the writing binary was trusted and each
login reset the ACL, making "Always Allow" wear off. -
On macOS,
ggshieldno longer asks for Keychain access again after every upgrade. The
code-signing identifier embedded a per-build hash, so the "Always Allow" grant recorded
for one release stopped matching the next one; it is now pinned to
com.gitguardian.ggshield. One grant made from a release built with this fix onwards
keeps working across upgrades. -
The AI hooks no longer create incidents on your dashboard when
secret.source_uuidis set
in your configuration (a setting shared with CI scanning): a hook event is not a source
scan, and every prompt and every file the agent read was creating an incident. They also
now always scan withall_secrets, so they can block on a secret that is already known to
GitGuardian instead of letting it through. -
tomliwas added to the dev dependency group, without a marker, so dev environments always have it regardless of the
Python interpreter, and ty can resolve the fallback branch it insists on analyzing -
secret scan ai-hooknow honourssecret.ignored_pathsfrom
.gitguardian.yaml, as every othersecret scancommand already did. A file
excluded there is no longer read, sent, or blocked on when an agent reads it.
Previously the setting was silently inert on this path.ignored_matchesand
ignored_detectorswere never affected. This also brings the default
exclusions to the hook: reads undernode_modules/,.venv/,vendor/,
.git/and the otherIGNORED_DEFAULT_WILDCARDSentries are no longer
scanned. Those defaults are matched against the path relative to the project
and with symlinks resolved, so a checkout that itself lives under a directory
namedvendor/,node_modules/or.venv/is still scanned normally, and a
symlink parked in a vendored tree cannot hide a file living outside it. -
On macOS,
ggshield auth loginno longer writes the token straight to the
Apple Keychain whenPYTHON_KEYRING_BACKENDselects another backend: the write
now follows the backend the token is read back from. Previously login reported
success while nothing could authenticate afterwards. -
keyringnow requires 25.0 or later, the first version carrying the
create_cfbinding the Keychain ACL is built with. On 24.x the ACL silently
never applied. -
AI discovery no longer reports MCP server configurations for agents that are not
installed. A project.mcp.jsonis read by several agents, and Copilot also declared a
hardcoded GitHub MCP server, so machines without those agents reported configurations
they could not run. -
On macOS and Windows,
ggshieldnow finds VSCode's user directory, so its global MCP
servers and its known workspaces are discovered there too. -
The
cryptographyshipped in the released binaries is now 50.0.0, fixing
CVE-2026-69247, a Bleichenbacher oracle in PKCS#7EnvelopedDatadecryption.
ggshield does not use that code path. -
The AI hook installed from the macOS standalone package now points at
/usr/local/bin/ggshieldinstead of the versioned/opt/gitguardian/ggshield-<version>/
directory an upgrade removes, so it keeps scanning after an upgrade. -
ggshield machine setupnow repoints an AI hook command whose ggshield binary is gone,
or is reachable through a more stable path, instead of leaving the broken command in
place. -
On macOS,
ggshield machine setupnow asks the Keychain for access as the binary
that actually runs the AI hook. Keychain grants are per binary, so the hook used to
raise its own authorization dialog inside an agent-spawned process, where the agent's
timeout could kill it before "Always Allow" was recorded and the dialog came back on
every prompt. -
ggshieldno longer reads the OS credential store on startup. The token is now
fetched when a command actually needs it, so commands that do not use one (such as
ggshield config list,ggshield plugin listandggshield install) no longer
trigger a macOS Keychain password prompt. -
ggshield secret scan ai-hookno longer leaves a whole event unscanned when the file path
it guessed from a Bash command or an@-mention cannot be read. Such a candidate is
dropped instead of being sent to the scanner, where the read error aborted the event and
allowed the action with a "could not scan" warning, so the command or prompt text of that
same event is now always scanned. A candidate longer than the filesystem's limits (a
heredoc mistaken for a file name) is also recognized as text without a filesystem call.