The Trust Boundary You Did Not Know You Had - Configuration Files, Pull Requests, and the Gemini CLI Hook CVE
The Trust Boundary You Did Not Know You Had
The Category Error at the Heart of It
Modern pull request review rests on a quiet assumption. The code in
the pull request is adversarial until human reviewers approve it. The
configuration in the pull request, by contrast, is treated as ambient
context. Linter configurations, formatter rules, editor settings,
agent preferences, CI helper files. Configuration looks declarative.
Configuration looks safe. The mental model that operators carry
forward from decades of PR workflows says that the lock on the door is
the merge button, and what comes through that door is code.
The Gemini CLI hook CVE that landed in May 2026 punctured that mental
model in a specific and important way. The vulnerability did not lie
in the AI model. It did not lie in the CLI's command parser. It lay in
a single architectural choice that, viewed with hindsight, was
inevitable from the moment AI agents started running in CI/CD
pipelines. The choice was to honor an .gemini/settings.json hook
field, which can execute arbitrary commands, present in the pull
request being reviewed.
A pull request author could include a beforeAgent hook in their PR
that ran whatever shell command they liked. The CI runner, executing
the Gemini CLI in headless mode against the PR contents, would dutifully
honor the hook. The runner held the organization's secrets. The runner
had network access. The runner was, for the duration of that workflow,
controlled by the attacker.
The fix Google shipped is a flag to disable workspace-supplied
settings by default. The flag is correct. The deeper issue it points
at is the one worth writing about.
What Counts as Code
There is a useful way to think about what counts as code in any given
system. Code is anything that can change the system's behavior in
ways the system's owner did not specify. A shell script is code.
A program is code. A configuration file that contains a command field
is code. A YAML file that contains an exec: directive is code. A
package manager lockfile is code, because the resolved versions
determine what gets fetched and run.
The category boundary between "code" and "configuration" was always
porous. It became permeable a long time ago when build tools started
running arbitrary shell from configuration files, and it has been
dissolving steadily ever since. The Gemini CLI hook is not an aberration.
It is the latest member of a long family that includes pre-commit
hooks, Makefile targets in tests, npm lifecycle scripts (preinstall,
postinstall), pip install hooks, GitHub Actions composite action
references, and dozens of others. Each of these is configuration that
runs commands. Each of these, in a pull request, becomes
attacker-controlled.
The AI agent case is more acute than its predecessors for one reason.
Agent settings files are designed to govern execution. They are not
incidentally executable. Their purpose is to tell the agent what tools
to run, when to run them, and what to do with the output. The
beforeAgent hook is not a vestigial leftover from some earlier
era. It is a feature, intentionally designed, that does what it says.
The fact that you can run a sandboxed command before the agent plans
is the point.
This places agent configuration files in a different category from
linter configuration or editor settings. They are not configuration.
They are programs. The Gemini CLI CVE is what it looks like when an
ecosystem treats a program file as a configuration file for one
release cycle too many.
Why YOLO Mode in CI Was Inevitable
The structural pressure behind the vulnerability is worth naming
explicitly. AI agents in CI/CD are useful precisely because they can
run tools. A PR review agent that cannot read files, query the
repository, run tests, or fetch additional context is a chat interface
glued to a webhook. The value of the agent comes from its ability to
take actions.
The standard mode for letting an agent take actions is to grant it
permission to run any tool it decides is appropriate. In Gemini CLI
this is called YOLO mode. In other agent frameworks it has different
names. The principle is the same. An agent that has to pause for
human approval at every tool call is not an autonomous agent. An agent
that is fully autonomous has, by definition, the capability to do
anything the runner can do.
CI/CD pipelines are headless. There is no human at the keyboard to
approve tool calls. Either the agent runs in YOLO mode, in which case
it can do anything, or it runs in approval-gated mode, in which case
it cannot run at all. The two requirements (agent autonomy and CI
headlessness) collide. The standard response of the industry has
been to grant autonomy and trust that the inputs are friendly.
The Gemini CLI hook CVE is what happens when the inputs are not
friendly. The fact that this took until May 2026 to surface as a
publicized CVE is more notable than the fact that it surfaced at
all.
The Supply Chain Context
The CVE does not exist in isolation. It belongs to a family of recent
supply chain attacks that share a structural pattern. The threat actor
tracked as TEAM-PCP has, over the last several months, compromised
LiteLLM, Trivy, Checkmarx, and Tinexx. The attacks differ in their
specifics but all exploit a single pattern. A CI/CD workflow trusts
something it should not, and the trust is exploitable through code
that an attacker can introduce into a build artifact or PR.
The Trivy compromise in March came through an Aqua Bot service that
allowed unprivileged interactions with the Trivy action repository.
The Checkmarx compromise propagated downstream into Axios because
Axios used the Checkmarx tool in its own CI. The LiteLLM compromise
appears to have come through the Trivy action, which was itself
compromised. Each link in the chain was a CI/CD trust boundary that
turned out to be more porous than it looked.
The Gemini CLI hook CVE is not part of this chain in the sense of
attribution, and there is no evidence as of this writing that
TEAM-PCP exploited it. The relevance is structural rather than
forensic. The same pattern keeps producing the same outcome. CI/CD
runners hold organizational secrets. CI/CD runners process
attacker-controlled inputs. CI/CD runners use tools that conflate
configuration with code. The pattern is the vulnerability. Specific
CVEs are individual manifestations of it.
What the Mitigation Actually Says
Google's fix is to require operators to opt into trusting workspace
settings. In run-gemini-cli versions 0.3.91 and 0.4.0-preview.3 and
later, the default is to ignore .gemini/settings.json in the PR
workspace. Operators who have legitimate reasons to trust workspace
settings (private repositories, internal teams, trusted collaborators)
can set gemini_trust_workspace: true and opt back in.
This is the right shape of fix for this specific issue. It also has
two operational consequences worth naming.
The first is that version pinning is a footgun here. Operators who
pinned to a specific Gemini CLI version, which is good practice
generally, are pinned to the vulnerable version until they update the
pin. The "we already patched it" announcement does nothing for an
organization whose CI workflow refers to an immutable pre-fix version.
The remediation requires explicit operator action, and any
organization that does not have a process for tracking and updating
pinned third-party action versions is still vulnerable today.
The second is that the trust flag does not address the broader
pattern. It addresses Gemini CLI's settings file. Every other agent
framework that supports configuration-driven tool execution has the
same problem until it ships an equivalent flag. Every CI/CD action that
reads configuration from the workspace it is processing has, in
principle, the same problem. The fix is per-tool. The vulnerability
is architectural.
The Question to Ask About Your Own Workflows
The useful exercise after reading this CVE is to look at your own CI
workflows and ask, for each tool that runs against pull request code,
the following question. What files in the workspace can change the
behavior of this tool?
For most teams the answer is more files than they realized. A
non-exhaustive list of file categories that are typically in scope:
.github/workflows/ modifications, which are blocked from running
during PR validation by GitHub's default policy but only if that
policy is enabled and only for the workflow files themselves. Other
files in the workflow can still influence the workflow's behavior.
Makefile, package.json scripts, pyproject.toml build hooks,
Cargo.toml build scripts, and the equivalent for every other
build system. Each of these allows an attacker to define commands
that run during the build phase of the PR validation.
pre-commit-config.yaml, which tells pre-commit what hooks to run,
each of which is potentially attacker-controlled if the upstream
repository is not pinned.
Editor and language server configurations such as .editorconfig,
.vscode/settings.json, pyrightconfig.json, and ESLint
configurations. Most of these are inert but each of them depends on
the consumer treating them as inert.
AI agent configurations, including but not limited to the Gemini CLI
case that prompted this post. Claude Code, GitHub Copilot Workspace,
Aider, Continue, and most other agent frameworks support some form
of project-level configuration that can influence agent behavior.
Container build configurations including Dockerfile, docker-compose.yml,
and Buildpack configurations, where the build itself is code execution.
This is not a list of things that are necessarily exploitable. It is
a list of things to look at when answering the question of what can
change the behavior of your CI tooling. The exploitable subset will
depend on the specific tools and the specific workflow.
Defense in Depth at the Runner Layer
The advice that the original commentary on this CVE landed on is
worth restating in different words. Assume the runner will be
compromised, and design accordingly. The CI/CD runner is not the
last line of defense. It is the place where defenses must be
prepared to fail.
Concretely, this implies several practices. Each runner should have
the minimum scope of credentials necessary for its job, scoped to
the specific repository and the specific actions it needs to take.
GitHub's fine-grained personal access tokens and the new
repository-scoped GITHUB_TOKEN permissions are the right level of
granularity. Long-lived organization-wide secrets in a CI environment
are a 2020 anti-pattern that should not survive to 2027.
Self-hosted runners should run in ephemeral containers or VMs, with
no persistent state between jobs, and should not share credentials
or filesystem state with other workloads on the host. A self-hosted
runner that survives a compromise long enough to read another
service's secrets is a runner that has failed its purpose.
PR validation workflows that need to run tools against untrusted code
should run in pull_request triggered workflows, which run with the
minimal permissions of the PR author's fork, rather than
pull_request_target triggered workflows, which run with the
permissions of the base repository. The temptation to use
pull_request_target is real, because it lets the workflow see the
base repository's secrets, which is precisely the reason it must be
avoided when the workflow processes attacker-controlled code.
Secrets in environment variables visible to the agent process should
be the absolute minimum the agent needs to do its work. The temptation
to put everything the agent might want into environment variables is
real and is the operational version of "we're using AI for everything".
Network egress from the runner should be controlled. A compromised
runner that cannot reach the attacker's exfiltration endpoint cannot
exfiltrate. Egress restrictions in self-hosted runner environments
are not difficult to implement and they substantially raise the cost
of post-compromise exploitation.
The Architectural Observation
The Gemini CLI CVE is, in the end, a small thing. A flag, a default,
a few CI workflows that need updating. The architectural observation
underneath it is larger.
The trust boundary in modern PR review has been quietly migrating for
years. It used to be that the boundary was the merge button. Code in
PR was untrusted; code in main was trusted. The boundary held because
the tools that processed PR code did not themselves execute it.
Linters parsed it. Compilers compiled it. Tests ran it inside narrow
sandboxes designed for the language ecosystem in question. The
boundary was clear and the tools respected it.
The boundary has eroded because the tools have grown capabilities.
Build tools now run arbitrary code from configuration. Package
managers run install hooks. Agents run hooks before they plan. Each
incremental capability seemed harmless in isolation. The aggregate is
that the PR validation environment is, today, a near-arbitrary
execution context where the attacker's code runs with the
organization's credentials.
The right response is to rebuild the trust boundary closer to where
it always should have been, which is at the credential and capability
level rather than at the code-versus-configuration distinction. The
runner should not have secrets it does not absolutely need. The
runner should not have network access it does not absolutely need.
The runner should be ephemeral. The agent should not run in YOLO mode
against untrusted input. These are not new ideas. They are the
hardening practices that the security community has been advocating
for years, applied now with new urgency because the tools that ignore
them have multiplied.
The Gemini CLI CVE is the warning. The pattern it points at is the
work.
Closing
If you operate AI agents in any CI/CD context, the next hour spent
auditing where your runners hold secrets and what workspace inputs
those agents trust will pay back many times. The patch is the easy
part. The question of what other tools in your pipeline share the
same fundamental assumption is the harder one and the more important
one.
The architectural fix is at the platform layer, not the application
layer. Tool-by-tool patches are necessary but insufficient. The
runners need to be hardened against the case where the tool itself
is the vector. That hardening is operational discipline of the kind
that does not have a CVE attached to it but produces the outcome
that the CVE is trying to retrofit.
There will be more CVEs in this family. The pattern is too useful to
attackers and the operational habits that enable it are too entrenched.
Building the trust boundary before the next CVE finds it is the work
worth doing now.