A branch named after a pinned commit SHA let plugin repo owners swap code in four AI coding agents. Claude Code and Codex are fixed; Copilot and Gemini CLI are not.
Pinning a plugin to a reviewed commit SHA is meant to guarantee that the code an AI coding agent installs is the code a marketplace reviewed. Air Security's research lab showed on 17 September 2026 that four of the best-known agents did not actually enforce that guarantee. A plugin repository owner could make Claude Code, OpenAI Codex, GitHub Copilot and Gemini CLI run different code while the pin still looked honoured. The researchers call it Plugin4Shell.
Anthropic and OpenAI have shipped fixes. Microsoft has not shipped one for GitHub Copilot, and Google says it will not patch Gemini CLI, which it is retiring. No CVE has been assigned.
Who is affected
| Agent | Status | Fixed in |
|---|---|---|
| Claude Code (Anthropic) | Patched | 2.1.179 |
| OpenAI Codex | Patched | 0.146.0 |
| GitHub Copilot (Microsoft) | No patch shipped | none |
| Gemini CLI (Google) | Will not be fixed; product retiring | none |
The exposure is limited to plugins whose source repository lives somewhere that accepts a branch name made of 40 hex characters. Air Security notes that GitHub rejects such branch names outright, but Bitbucket and any self-hosted Git server allow them. A plugin hosted on GitHub cannot be hijacked this way; one hosted on Bitbucket or a private Git server can.
How the pin gets bypassed
Each of the four agents installs a marketplace plugin by cloning its repository and checking out the commit the marketplace pinned. For Claude Code, Codex and Copilot, Air Security describes the sequence as a clone followed by git checkout <40-character SHA>.
The flaw is in what Git does with that argument. When a branch exists with the same name as the requested commit hash, Git resolves the name to the branch, not to the commit. An attacker who controls the plugin's repository creates a branch named exactly after the pinned SHA, points it at malicious code and makes it the default branch. The agent asks for the reviewed commit, receives the attacker's branch, and nothing in the install tells the user anything changed.
Gemini CLI is reached by a second variant. It fetches the pinned ref and then runs git checkout FETCH_HEAD. If the repository's default branch is itself named FETCH_HEAD, the checkout resolves to that branch and the fetched commit is silently discarded.
How a branch named after the pinned SHA redirects the install. Source: Air Security.
Why it is zero-click
The swap does not wait for a fresh install. Agents update installed plugins in the background, and in Claude Code and Codex that auto-update is on by default. The same checkout runs again on every update, so a plugin that was benign when a user installed it can turn malicious later without the user doing anything.
Air Security describes two ways to get there:
- Publish, then turn. Contribute a genuinely benign plugin to a trusted marketplace, pass review, and later swap in a malicious version behind the same pin.
- Hijack a trusted repository. Take over the repository behind a plugin someone else wrote and the marketplace already trusts, then use Plugin4Shell to push the malicious version to every agent that has it installed. The researchers point to their earlier "SkillJacking" work, in which 925 skills already in use were hijacked from their maintainers, affecting 134,000 agents.
The fix, and why only two vendors have it
The defence is a single assertion. After the checkout, resolve the commit actually present in the working tree and abort unless it equals the pinned SHA. Air Security stresses that it has to check the resolved HEAD, not the ref that was requested; that one check closes both variants.
OpenAI's fix does exactly that. Codex pull request #34644, "Verify Git plugin SHA checkouts", merged on 22 July 2026, resolves HEAD after checking out a SHA-pinned plugin source and rejects the source when the commit does not match. Its description says Git "can interpret a requested commit SHA as a branch name when the remote's default branch has the same name", which "can cause a marketplace plugin source to materialize a different commit than the one it pinned." The change shipped in Codex 0.146.0, released on 29 July 2026, and Air Security verified it on 12 August.
Anthropic confirmed the Claude Code fix in version 2.1.179 on 17 June 2026, according to Air Security. The public Claude Code changelog for 2.1.179 does not list the change.
Microsoft received the same disclosure for GitHub Copilot and, as of publication, had not shipped a fix. Google told the researchers on 4 August that it would not fix Gemini CLI and advised users to move to Antigravity CLI, which Air Security says the attack does not reach. That leaves a gap: Google stopped serving Gemini CLI to free, Google AI Pro and Ultra users on 18 June 2026, but customers with Gemini Code Assist Standard or Enterprise licences, or access through Google Cloud, keep using it. Those installs carry the flaw with no patch coming.
Timeline
| Date | Event |
|---|---|
| May 2026 | Air Security finds the flaw and builds a working proof of concept |
| June 2026 | Disclosed to Anthropic, OpenAI, Microsoft and Google |
| 17 June 2026 | Anthropic confirms the Claude Code 2.1.179 fix |
| 22 July 2026 | Codex fix (#34644) merged |
| 29 July 2026 | Codex 0.146.0 released |
| 4 August 2026 | Google confirms no Gemini CLI fix |
| 12 August 2026 | Air Security verifies the Codex fix |
| 17 September 2026 | Plugin4Shell published |
From the first fix to publication: two agents patched, Copilot still waiting. Sources: Air Security; openai/codex on GitHub.
What to do
- Update Claude Code to 2.1.179 or later and Codex to 0.146.0 or later. Check the version on every developer machine and CI runner, not only your own; background auto-update is what made the flaw zero-click, and it is also what delivers the fix.
- Inventory where your plugins are hosted. A plugin sourced from Bitbucket or a self-hosted Git server is in scope; one sourced from GitHub is not. For Copilot, where there is no patch, prefer plugins hosted on GitHub or remove the rest until Microsoft ships a fix.
- Move off Gemini CLI. Enterprise and Google Cloud users who still run it should plan the migration to Antigravity CLI now; Google will not patch this.
- Treat a pinned SHA as a request, not a proof. Anywhere your own tooling clones a repository and checks out a hash, including CI scripts and internal installers, add the same check the vendors added: compare
git rev-parse HEADwith the expected SHA after checkout and fail if they differ. - Watch plugin repositories you depend on for default-branch changes and for branches named like commit hashes or
FETCH_HEAD. Either is a strong signal of tampering.