DevelopmentAI Agents

Plugin4Shell: Zero-Click Flaw in Claude Code, Codex, Copilot

Plugin4Shell turns plugin SHA pinning into an illusion: a branch named like the pinned commit makes git swap in attacker code while the agent reports the audited version installed. Here is how it works, who has patched, and what to check today.

Toolbit AI - Team
9 min read
Plugin4Shell: Zero-Click Flaw in Claude Code, Codex, Copilot

A plugin that looks verified can quietly be something else entirely. Plugin4Shell, disclosed by security startup AIR on September 17, 2026, is a zero-click remote code execution flaw that hits the plugin systems of Claude Code, OpenAI Codex, GitHub Copilot, and Gemini CLI, and it works by turning the ecosystem's main defense against itself.

In short:

  • Plugin4Shell is a SHA-pinning bypass: marketplaces pin plugins to an exact 40-hex commit hash so only audited code runs, but the four agents never verified the checkout actually landed on that hash.
  • An attacker who controls a plugin repo can name a branch exactly like the pinned SHA and make it the default, so git resolves the checkout to the attacker's branch while the agent reports a successful pinned install.
  • In Claude Code and Codex, plugin auto-update runs in the background by default, which makes the swap zero-click: the benign plugin only needs to already be installed.
  • Codex 0.146.0 is fixed, vendor-confirmed. Claude Code 2.1.179 is reported fixed by AIR, though Anthropic's changelog is silent on it. GitHub Copilot has no patch. Gemini CLI is deprecated and will not be fixed.
  • No CVE, and no public evidence of in-the-wild exploitation, as of September 21, 2026.

Why does a defense built for exactly this threat fail so completely? The answer is one unverified assumption in how the agents use git.

What is Plugin4Shell, and why does the trust model break here?

Marketplaces for agent plugins and skills added SHA pinning for a reason: AIR's earlier research had already shown how easy it is to plant or hijack a skill and spread it to thousands of agents. Pinning a plugin to a specific commit hash means the reviewed code is the code that runs, and if the repo is later compromised, the pin keeps pointing at the audited version. It is the same idea as locking a dependency to an exact version instead of a moving tag.

Plugin4Shell breaks that promise at the checkout step. Every affected agent fetches the plugin and runs git checkout on the pinned SHA, but none of them verifies that the working tree actually landed on that commit. The security control reports success while failing silently. That is what makes this a supply chain flaw rather than a normal bug: it attacks the distribution layer, not the model or the agent itself. AIR calls it the first supply chain vulnerability of the AI agent ecosystem, and the mechanics back the claim up.

One naming note before going further: Copilot here means GitHub Copilot and its CLI, not Microsoft 365 Copilot.

How a branch named like a commit SHA defeats the checkout

Flow diagram comparing the vulnerable SHA checkout path with the fixed path that verifies the resolved commit

The trick works because of how git resolves names. When a name is both a valid ref and a 40-hex object id, git prefers the ref and prints only a "refname is ambiguous" warning. An attacker who controls a plugin's repository can create a branch whose name is exactly the pinned SHA and set it as the repository's default branch.

Two preconditions have to hold: the hosting platform must allow branch names that look like hashes, and the branch must be the default. GitHub blocks SHA-shaped branch names outright, which is why GitHub-hosted plugins are not exposed to this variant. But Bitbucket and self-hosted git servers, both officially supported marketplace backends for some of these agents, do allow them.

A non-default branch would not work, because a clone only records non-default branches as remote-tracking refs; the checkout falls back to the commit. A default branch named like the hash is brought down as a local branch, and the checkout silently lands on attacker code. The agent's UI keeps showing the pinned hash as the honored pin, so nothing looks wrong.

Gemini CLI has a variant with the same result: its installer clones the repo, fetches the pinned commit, and then checks out FETCH_HEAD. If the repo's default branch is named exactly FETCH_HEAD, the checkout resolves to the attacker's branch and the fetched commit is silently discarded.

The fix is one assertion: after the checkout, resolve what the working tree actually points to and abort on mismatch.

test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort

OpenAI shipped exactly this in Codex, in a pull request merged on July 22, 2026 that resolves HEAD after every SHA-pinned checkout and rejects the install on mismatch. That vendor-confirmed fix is the strongest public evidence that the mechanism is real.

Why it's zero-click: background auto-update

SHA pinning was meant to stop silent swaps. Auto-update is what makes them silent anyway. In Claude Code and Codex, plugin auto-update runs in the background by default. When the marketplace bumps the pinned SHA, the same vulnerable checkout re-runs with no install step and no prompt. The already-installed plugin, reviewed and trusted on day one, silently pulls different code.

That is why the flaw matters even to teams that never install anything new: the benign plugin only needs to already be installed. The scope claim is worth keeping precise: the flaw affects all four agents, but the zero-click delivery rides specifically on the auto-update defaults in Claude Code and Codex. Press coverage sometimes blurs that line, so it is worth repeating it plainly.

Patch status: what's fixed, what isn't (as of Sep 21, 2026)

Ledger of patch status across Claude Code, Codex, GitHub Copilot and Gemini CLI as of September 21 2026

The patch picture is uneven, and the details matter more than the headline:

AgentStatusVersionSource
OpenAI CodexFixed0.146.0Vendor-confirmed via PR #34644
Claude CodeFixed per AIR2.1.179AIR's account; Anthropic's changelog is silent
GitHub CopilotUnpatched-No Microsoft patch as of Sep 21, 2026
Gemini CLIWon't fix-Deprecated; Google advises migrating to Antigravity

Claude Code's 2.1.179 entry deserves a caveat. AIR reports that Anthropic confirmed the fix to them in June 2026, and the version's build date lines up. But Anthropic's public changelog for 2.1.179 mentions connection drops, WSL2 scrolling, and plugin loading performance, not SHA verification. Until Anthropic says something public, "fixed in 2.1.179" rests on AIR's account alone. If you run Claude Code, updating is still the right move, but the attribution should stay honest.

Copilot's situation is worse because there is no fix to attribute. AIR says Microsoft has not shipped a patch and has not responded substantively to the disclosure. GitHub's position, relayed by The Register, is that SHA-shaped branch names are blocked on GitHub, so the reported vulnerability cannot be exploited there. AIR's counter is that marketplaces can be hosted on Bitbucket and self-hosted git too, which those agents officially support.

Gemini CLI users get the bluntest outcome: Google deprecated the tool and told AIR it will not patch it, so every install stays exposed indefinitely. If you still run Gemini CLI, treat it as permanently vulnerable and plan the migration.

One more caveat that applies across the whole matrix: Microsoft has said nearly 90 percent of the Fortune 500 use Copilot, a figure relayed by The Register, but that is a vendor's own marketing number, not an independent measurement.

What your team should check right now

  1. Update Claude Code to 2.1.179 or later and Codex to 0.146.0 or later. These are the only complete agent-side fixes that exist today.
  2. Manually verify installed pins. In each installed plugin's checkout, run git rev-parse HEAD and compare it to the SHA in the marketplace manifest. A correct pinned install leaves the repo in detached HEAD at the recorded SHA; HEAD pointing to a branch is the investigation signal.
  3. Audit where plugin repos are hosted. GitHub-hosted plugins are protected by the branch-name block. Bitbucket and self-hosted git are not. Check where your plugin dependencies live, not just where your own code sits.
  4. Scan plugin repos for hostile branch names. As a repo owner, any branch name matching a 40-hex pattern, or the exact string FETCH_HEAD, is a red flag.
  5. If you run Copilot, treat it as unpatched. Audit installed plugins, remove unused ones, and consider disabling background auto-update until a fix ships.
  6. If you run Gemini CLI, plan the migration. Google's advice is to move to Antigravity; until then, isolate the CLI from anything sensitive.

There is one open question worth flagging: it is not public whether updating an affected agent also removes an already-swapped plugin, or only prevents future swaps. Until a vendor answers that, the manual rev-parse check in step 2 is the only way to know your working tree is clean.

One flaw, four engineering teams

The uncomfortable part of Plugin4Shell is not the git mechanics. Four separate engineering teams, at four separate companies, built the same trust assumption into their install pipelines: that a pinned hash guarantees the code you get is the code you asked for. None of them noticed until an outside lab forced the issue. The same assumption failure is exactly why prompt injection keeps working: a system that reports success cannot be trusted to verify itself.

If you want to go deeper on what these agents can do when they are not being attacked, our Claude Code capabilities guide and the multi-agent projects walkthrough cover the productive side of the same tools. And if you're new to agent infrastructure generally, start with what an agent actually is in Toolbit's directory of AI agents and tools.

Frequently Asked Questions

Is there a CVE for Plugin4Shell? No CVE has been assigned as of September 21, 2026. The disclosure is documented through AIR's publication and vendor patch notes rather than a CVE entry, which is common for coordinated disclosures that vendors fix quickly.

Is my plugin safe if its repo is hosted on GitHub? For Plugin4Shell's branch variant, yes: GitHub does not allow branch or tag names that resemble commit SHAs, so the branch-named-as-hash trick cannot be staged there. That protection covers only this variant and only GitHub-hosted repos; it is not a general guarantee that a plugin is safe.

Does updating my agent remove an already-swapped plugin? The public sources do not say, and no vendor has clarified it. Treat the question as open: update the agent to stop future swaps, and run the manual git rev-parse HEAD comparison from the checklist above on every installed plugin to know what is actually in your working tree today.

Can marketplaces fix this on their own? No. The pin resolves on the client side, inside the agent, so the verification has to happen in the agent itself; a marketplace can only blunt the attack by restricting which git hosts it pulls from. AIR's position is that a marketplace-side restriction cannot fully close the gap because the agents officially support non-GitHub hosts.

Share this article

Related articles

Continue exploring similar guides and insights