Skip to main content
  1. Articles/

Plugin4Shell: The First Supply-Chain Bug Built for AI Coding Agents — and a Clean Patch-Gap Between Vendors

·1197 words·6 mins·
Florent Clairambault
Author
Florent Clairambault
CTO & software engineer — writing daily about spec-driven development and agentic coding

Plugin4Shell: The First Supply-Chain Bug Built for AI Coding Agents — and a Clean Patch-Gap Between Vendors

Every AI coding agent that supports plugins does the same thing to make you trust an update: it pins the plugin to a specific Git commit hash. Lock the SHA, the theory goes, and the code can’t change out from under you without you noticing. Air Security’s September 17-18 disclosure of Plugin4Shell shows that theory was wrong for four of the biggest agents on the market — and that the four vendors responded to the same bug in four completely different ways.

The bug: Git will happily lie to you about what a SHA means
#

Plugin4Shell isn’t a cryptographic break. It’s a Git-semantics trick. When most agents update a pinned plugin, they run the equivalent of git checkout <pinned-sha> and trust that whatever ends up in the working directory is the commit they asked for. Git doesn’t work quite that literally: if a repository has a branch or ref whose name happens to match the pinned SHA, Git will resolve the checkout to that named reference instead of the raw commit object. An attacker who controls the plugin’s repository — a compromised maintainer account, a takeover of an abandoned package, or just a malicious publisher from day one — can create a branch named after the exact 40-character hash victims have pinned, point it at whatever code they want, and the agent will report “verified, pinned to <sha>” while executing something else entirely.

Air Security found a second variant hitting Gemini CLI specifically: instead of validating a checked-out SHA, the agent fetches a commit and checks out FETCH_HEAD without confirming it matches. Naming a repository’s default branch FETCH_HEAD produces the same result — a checkout that resolves to attacker-controlled code while the pin looks intact.

The fix for either variant is one line: verify git rev-parse HEAD equals the pinned SHA after checkout, and abort if it doesn’t. That it took a dedicated disclosure to surface a missing assertion this simple is the real story here — not the cleverness of the bug, but how uniformly it was missed.

The disclosure timeline, and the part that makes this a real test case
#

Air Security’s own account, corroborated by The Hacker News and Help Net Security, lays out a clean private-disclosure-to-public-report arc: the vulnerability was discovered with a working proof-of-concept in May 2026, coordinated disclosure to all four vendors began in June, and public disclosure landed September 17-18 — a roughly three-and-a-half month window, well inside normal responsible-disclosure norms. No CVE has been assigned as of publication, and none of the four vendors has published a formal security advisory; everything below comes from Air Security’s writeup and vendor actions it documents, not from vendor-issued bulletins.

That gives four vendors the same bug, the same lead time, and wildly different outcomes:

AgentStatusFix confirmed
Claude CodeFixedv2.1.179, confirmed working June 17, 2026
OpenAI CodexFixedv0.146.0, verified working August 12, 2026
GitHub CopilotNo fix shippednone planned as of disclosure
Google Gemini CLIWon’t be fixedGoogle is deprecating Gemini CLI entirely, telling users to migrate to Antigravity, which Air Security notes wasn’t built with the plugin-pinning system this attack relies on

Claude Code’s fix landed roughly two months after coordinated disclosure began and was independently confirmed working by Air Security before September’s public writeup — the version most consistent with how responsible disclosure is supposed to go. Codex followed about a month later. GitHub’s copilot has had the same lead time and, per Air Security, has no patch and no committed timeline. Google’s answer isn’t a patch at all — it’s telling existing Gemini CLI users their tool is going away, which resolves the vulnerability for Google’s roadmap but does nothing for anyone still running it in the meantime.

There’s a structural note buried in the writeup worth flagging honestly rather than treating as a clean Anthropic win: Air Security also found that GitHub itself blocks branch names that resemble commit hashes, which limits Plugin4Shell’s blast radius for any plugin actually hosted on GitHub. The exploit’s practical reach is Bitbucket and self-hosted Git servers that permit that naming pattern. So Copilot’s exposure through GitHub-hosted plugins is narrower than the headline “four major agents affected” suggests — the lack of a fix is still a real gap, just a smaller one for GitHub-centric workflows than for anyone pulling plugins from elsewhere.

Not an isolated finding — the third act in a pattern
#

Plugin4Shell is the culmination of a sequence Air Security has been building for months, and treating it in isolation undersells how much groundwork preceded it. In an earlier exercise the firm calls “The Story of Skills,” researchers planted a malicious skill in a trusted marketplace, watched it spread organically, and ended up controlling more than 26,000 agents before pulling the plug. Building on that, a follow-up technique dubbed SkillJacking — repository takeover of existing, previously trusted plugins rather than planting new malicious ones — found 925 skills already in active use had been hijacked out from under their maintainers, reaching an estimated 134,000 agents. Plugin4Shell is presented as the underlying design flaw that makes both of those attack classes possible even against agents that think they’re protected by SHA pinning: the verification the ecosystem was relying on to stop exactly this kind of takeover doesn’t actually verify anything.

Read together, the three disclosures describe an attack surface that’s specific to how agentic coding tools distribute extensibility — plugins and skills pulled from mutable, third-party-controlled repositories and trusted based on a pin that turns out to be checkable in name only. This is the same category of problem this blog has tracked since May’s MCP STDIO command-injection crisis and September’s still-open GitSpawn git-config sink in Claude Code’s own /ultrareview: the trust boundary that matters in agentic tooling isn’t the model, it’s everything the model is allowed to pull in and execute on the way to doing its job.

Why the patch gap is the actual headline
#

This blog argues, consistently, that Anthropic’s terminal-native, permission-gated approach to agentic coding is the more defensible architecture — and it argues just as consistently that this doesn’t mean giving Claude Code a pass when it ships a real bug. Plugin4Shell is a case where both halves of that stance hold up cleanly at once: Claude Code had a genuine, exploitable supply-chain flaw, and Anthropic fixed it within the disclosure window with independent confirmation, the same as OpenAI managed for Codex a month later. What’s left exposed isn’t Anthropic’s product — it’s GitHub Copilot, still unpatched with no committed date, and Gemini CLI, whose fix is “stop using this tool.” If you’re running Copilot against plugins hosted anywhere other than GitHub itself, or you have Gemini CLI installations still in production, that’s the actual, current, unresolved exposure — not a hypothetical.


Sources: Air Security — “Plugin4Shell” (primary, disclosure writeup with full technical detail and timeline); The Hacker News — “Plugin4Shell Lets Repository Owners…” (Sept 18, 2026, corroboration); Help Net Security — “Zero-click RCE vulnerability hit four major AI coding agents, two remain unpatched” (Sept 18, 2026, corroboration, vendor-response detail); this blog’s prior coverage of the MCP STDIO command-injection crisis and the still-unpatched GitSpawn Claude Code RCE.

Related