Plugin4Shell: A Pin Is Not a Verification

SCIENCE & TECHNOLOGY · SEPTEMBER 22, 2026

A cutaway diagram of a pin tumbler lock shown in the unlocked position, with the key inserted and each spring-loaded pin pushed to align exactly at the shear line
Wapcaplet and Mats Halldin, dual-licensed GFDL / CC BY-SA 3.0, via Wikimedia Commons.

On September 17, 2026, the AI-agent security firm AIR Security disclosed "Plugin4Shell" — a zero-click vulnerability in the plugin systems of four AI coding agents: Claude Code, OpenAI Codex, GitHub Copilot, and Gemini CLI. All four let a developer extend the agent with third-party plugins pulled from a git repository, and all four let the plugin's manifest pin that plugin to an exact commit — a 40-character SHA hash — specifically so a marketplace listing can't be swapped for something else after it's been reviewed. Plugin4Shell broke that promise: under the right conditions, the agent would report that it had checked out the pinned commit while a different one sat on disk.

What SHA-Pinning Was Supposed to Stop

A plugin marketplace's whole security model rests on one assumption: the code a reviewer looked at is the code that runs. Pinning to a commit SHA, rather than a branch name like main, is how that assumption gets enforced — a SHA identifies one specific, immutable snapshot of a repository's history, so a plugin author can't quietly push new code to the same branch after approval and have every existing installation silently pick it up. It's the same reason a `package-lock.json` pins to a resolved hash instead of a version range. The pin is the whole point.

The bug lived in how each agent turned that pinned SHA into an actual checkout. Git resolves a string you hand it as a reference name — a branch or tag — before it tries to resolve it as a raw object ID. So if a repository's default branch happens to be named after the exact 40-character string a plugin was pinned to, git checkout <sha> checks out that branch, not the commit. Git does print a warning that the reference is ambiguous — but none of the four agents re-read HEAD afterward to confirm it had landed on the object it asked for. The pin was recorded as honored while a different branch's code sat on disk. Gemini CLI had its own variant: it fetched the plugin and then ran git checkout FETCH_HEAD, which a branch literally named FETCH_HEAD hijacks the same way.

Why this only bites on some git hosts. GitHub refuses to let anyone create a branch or tag whose name looks like a 40-character commit hash, which is why GitHub-hosted plugins mostly dodge this. Bitbucket and self-hosted git servers impose no such restriction — and Anthropic's own plugin-marketplace documentation explicitly supports pinning a plugin's SHA from "GitLab, Bitbucket, and self-hosted servers," describing the process as fetching and checking out the pinned commit with no mention of verifying what actually landed. That's the exact gap.

Two ways an attacker gets a hostile branch into place: submit a plugin that passes review honestly, then create the collision branch and swap the code later; or simply compromise a legitimate plugin author's repository. Either path needs the victim to already have that plugin installed with auto-update on — which is the default, and is why AIR calls it zero-click. The agent's own background update check does the swap on its own.

Who's Actually Patched

OpenAI's fix is the clearest evidence of what the bug was, because it's the one vendor whose patch is a public, readable diff. Pull request #34644, "Verify Git plugin SHA checkouts," merged into the Codex repository on July 22, 2026 and shipped in Codex 0.146.0 on July 29. Its own description is close to a plain-English writeup of the entire vulnerability: "Git can interpret a requested commit SHA as a branch name when the remote's default branch has the same name... Resolve HEAD after checking out a SHA-pinned Git plugin source and reject the source when the resolved commit does not exactly match the requested SHA." Four lines, and the bug is gone: check what you actually got, not what you asked for.

Anthropic's side of the story is less visible. AIR's disclosure timeline says Anthropic confirmed a fix in Claude Code 2.1.179 on June 17, and that version was published to npm on June 16 — the dates line up. But Claude Code is closed source, so there's no diff to read, and the version's own public changelog entry lists nine items, all UX and stability fixes — a scrolling glitch on WSL2, a sandbox glob bug, a feedback survey banner — with nothing about git, SHA verification, or plugin integrity. No security advisory exists for it either. The fix may well be there; Anthropic's own records just don't say so.

GitHub Copilot has no patch as of this writing. GitHub's public statement to reporters was that GitHub itself blocks the SHA-lookalike branch names that make the attack possible — true, but it only protects GitHub-hosted plugins, which was never the part of the attack surface AIR was pointing at. Gemini CLI isn't getting fixed either, for a more interesting reason: Google told AIR in August that it won't patch it, because Gemini CLI is being wound down in favor of a successor called Antigravity CLI. Individual accounts lost access in June; anyone still running it on an enterprise Code Assist license, however, is running an unpatched agent with no fix coming.

Sizing the Alarm Correctly

Nobody — not AIR, not the four vendors, not the trade press that covered it — has reported this being exploited in the wild. AIR built working proof-of-concept exploits against all four agents as part of a coordinated disclosure that started in June and only went public in September, the standard shape of a responsibly handled bug. There's also no CVE number attached to it. I checked the National Vulnerability Database's own API directly and it returns zero results for "Plugin4Shell," and neither the Claude Code nor the Codex GitHub repository has a security advisory that names it — notable mainly because Anthropic does routinely file CVEs for Claude Code (there are thirty on record, including one for an unrelated git-related sandbox escape from the same June). A bug this shaped, in tools this widely embedded in developer workflows, moving through the ecosystem on a startup's blog post and a four-line pull request description rather than any of the usual advisory channels, is itself worth noticing.

Where I Could Be Wrong

Sources

  1. AIR Security. Plugin4Shell. September 17, 2026. air.security
  2. OpenAI. Pull request #34644, "Verify Git plugin SHA checkouts." Merged July 22, 2026. github.com/openai/codex
  3. OpenAI. Codex 0.146.0 release notes. July 29, 2026. github.com/openai/codex
  4. Anthropic. Claude Code CHANGELOG.md (entry for 2.1.179). raw changelog
  5. Anthropic. Claude Code plugin marketplaces documentation (SHA-pinning against GitLab/Bitbucket/self-hosted sources). code.claude.com
  6. National Vulnerability Database. Keyword search for "plugin4shell," zero results as of September 22, 2026. nvd.nist.gov API
  7. GitHub Security Advisories, anthropics/claude-code. GHSA-7835-87q9-rgvv / CVE-2026-55607 (an unrelated sandbox-escape advisory, cited to show Anthropic does file CVEs when one exists). github.com
  8. Lyons, Jessica. "AI coding agents' 0-click RCE flaw could hand attackers keys to the kingdom." The Register, September 17, 2026. theregister.com
  9. Khandelwal, Swati. "Plugin4Shell Lets Repository Owners..." The Hacker News, September 18, 2026. thehackernews.com
  10. Markovic, Sinisa. "Plugin4Shell: AI coding agents vulnerability." Help Net Security, September 18, 2026. helpnetsecurity.com
  11. Masiero, Manuel. "Critical flaw in Claude Code, OpenAI Codex, GitHub Copilot and Gemini CLI." heise online, September 21, 2026. heise.de
  12. Google. "An important update: transitioning Gemini CLI to Antigravity CLI." Google Developers Blog. developers.googleblog.com
  13. AIR Security. SkillJacking. (Prior research from the same firm, cited for its track record.) air.security
  14. SecurityWeek. "AI Agent Firewall Startup AIR Security Emerges From Stealth With $50 Million." securityweek.com

Keep reading