A missing one-line check in four major coding agents turned plugin SHA-pinning into theatre. Claude Code 2.1.179 and Codex 0.146.0 are patched; GitHub Copilot has no fix and Gemini CLI never will. Here's the version audit, the plugin inventory, and the policy call every team running agents needs to make this week.
Last Updated: September 21, 2026
Researchers at AIR disclosed Plugin4Shell, a zero-click remote code execution flaw in the plugin systems of Claude Code, OpenAI Codex, GitHub Copilot and Gemini CLI. All four agents check out the pinned plugin commit but never verify that the checkout actually landed on it, so an attacker who controls a plugin repo can make a branch named like the pinned hash win the resolution and run their code while the agent reports a clean, pinned install. Anthropic fixed it in Claude Code 2.1.179 and OpenAI in Codex 0.146.0. Microsoft has shipped no Copilot fix and Google deprecated Gemini CLI rather than patch it. If you run coding agents, today's work is a version audit, a plugin inventory, and a written policy decision on the two unpatched products.
What was actually disclosed
Per Help Net Security, AIR's research lab found the same design error in all four leading coding agents: the agent clones a plugin repository, checks out the SHA the marketplace pinned, and then trusts that the checkout did what it was told. It never asks git where HEAD ended up.
That missing question is the whole bug. In git, when a name is both a valid ref and a valid object ID, the ref wins — you get an "ambiguous refname" warning and nothing else. So an attacker who controls the upstream plugin repo creates a branch whose name is the exact 40-hex pinned commit, makes it the default branch, and points it at malicious code. The plain clone brings that branch down locally, git checkout <sha> resolves to the branch, and the agent happily reports a successful install at the reviewed commit. Gemini CLI has a separate variant of the same failure: it fetches the pinned commit and then runs git checkout FETCH_HEAD, which resolves to a branch named FETCH_HEAD if the repo has one, quietly discarding the commit it just fetched.
AIR frames it as a first — "It is the first supply chain vulnerability of the AI agent ecosystem," the researchers said. The framing is marketing-adjacent, but the mechanism is not. This is a client-side verification failure in a distribution layer that now reaches millions of developer machines and CI runners.
The attack chain, as AIR documents it
The attacker publishes a genuinely useful plugin that passes review — or takes over the repo behind a plugin someone else already wrote.
Every install is locked to the reviewed SHA. The security model looks like it is working.
A second, still-benign commit ships. The marketplace maintainer approves the PR that re-pins to it.
The attacker creates a branch named after the new pinned SHA, makes it the default, and fills it with malicious code. The pinned commit itself stays untouched and auditable.
Background auto-update — the default in Claude Code and Codex — re-runs the checkout on machines that already have the plugin. No prompt, no install step, no signal.
Why this one is worse than the usual plugin scare
Most agent security stories punish careless behaviour: someone installed a random skill, pasted an untrusted MCP server, ran an agent with --yolo. Those are correctable with policy. This one punishes the teams that did the mature thing. If you stood up an internal marketplace, reviewed plugin source, and pinned to a reviewed commit, you built your control on a primitive that did not hold. Every downstream process that inherited the pin — change control, SBOM entries, your "we only run vetted plugins" slide — inherited the failure with it.
Doing the right thing does not protect you.
— AIR research lab, Plugin4Shell disclosure
The other reason to take it seriously is that the surrounding steps are already proven at scale. AIR's prior work is the supply half of the chain: a malicious skill it built reached more than 26,000 agents, and its SkillJacking research found 925 in-use skills hijacked from their original maintainers across 134,000 agents. Plugin4Shell is the part that defeats the containment mechanism built to stop exactly that.
Vendor status, and what each one means operationally
| Agent | Status | What you do about it |
|---|---|---|
| Claude Code | Patched in 2.1.179 | Pin your fleet to ≥ 2.1.179 and verify on every dev machine and CI image. Auto-update is the default, which cuts both ways — it delivered the fix to most users already. |
| OpenAI Codex | Patched in 0.146.0 | Same: enforce a floor version in provisioning and in your CI base images, not just on laptops. |
| GitHub Copilot | No fix shipped | Treat plugin installs as unpinned code execution. Disable marketplace plugins where you can, restrict to first-party-hosted repos, and get the exception in writing. |
| Gemini CLI | Deprecated, will not be patched | Migration decision, not a patch decision. Google points users to Antigravity, which has no plugin SHA-pinning to bypass. Every remaining install stays exposed indefinitely. |
The Gemini CLI response deserves a moment. "Deprecated" is not a mitigation for the machines still running it, and deprecation notices do not uninstall binaries from CI containers built eight months ago. If you have Gemini CLI anywhere in a pipeline, that is now an inventory-and-removal task with a hard deadline, not a roadmap item.
The honest caveats
Three things the disclosure is careful about, and one thing it is quiet about.
Exploitability depends on the git host. The branch-name variant only works where a branch can be named like a 40-hex hash. AIR notes GitHub rejects such names outright, while Bitbucket and self-hosted git servers allow them — and marketplaces on those hosts are a supported configuration. So a GitHub-only plugin supply chain blunts the Claude Code/Codex/Copilot variant. It does nothing for the Gemini CLI variant, because FETCH_HEAD is a perfectly ordinary branch name anywhere.
No confirmed in-the-wild exploitation is claimed. AIR reports working proof-of-concept exploits against all four agents, found in May 2026 and disclosed in June under coordinated disclosure. Proven mechanism plus proven takeover techniques is a serious combination, but it is not the same as an incident. Say that plainly to your stakeholders rather than letting the word "zero-click" do the arguing.
The researchers sell the remedy. AIR states that enterprises using its marketplace and filtering products were not affected. That does not weaken the technical finding — the git behaviour is verifiable in a minute on your own machine — but it does mean the "no marketplace can fix this" framing arrives with a commercial edge. The load-bearing claim is narrower and correct: because the pin is resolved on the client, only an agent-side assertion restores the guarantee.
What nobody has addressed: the agents reported a successful install at the pinned commit while running attacker code. That means your logs lied. Any retrospective hunt across the exposure window has to reconcile on-disk plugin content against the pinned SHA, because the install telemetry is not evidence of anything.
# Reconcile what is actually checked out against what was pinned.
# Run across plugin/skill directories on dev machines and CI images.
for d in $(find "$HOME" -maxdepth 6 -type d -name .git 2>/dev/null); do
repo=$(dirname "$d")
head=$(git -C "$repo" rev-parse HEAD 2>/dev/null)
branch=$(git -C "$repo" rev-parse --abbrev-ref HEAD 2>/dev/null)
# Flag any local branch whose name looks like a commit hash, or is FETCH_HEAD
git -C "$repo" for-each-ref --format='%(refname:short)' refs/heads \
| grep -E '^([0-9a-f]{40}|FETCH_HEAD)
