Plugin4Shell: when SHA pinning fails on Claude Code, Codex, Copilot, and Gemini CLI
Air Security’s Plugin4Shell disclosure (public Sep 17, 2026) is the supply-chain note I wish every desk running coding agents had already filed. The bug is not “don’t install shady plugins.” It is: you install a reviewed plugin, the marketplace pins a commit, the agent checks out that pin — and still lands attacker-controlled code. Zero click once auto-update is on. Full host compromise for whatever the agent can reach.
That hits the four names most production fleets actually use: Anthropic Claude Code,
OpenAI Codex, GitHub Copilot (CLI path), and Google Gemini CLI. Same design miss
across the board — checkout the pin, never assert that
git rev-parse HEAD equals the pinned SHA. Git’s ref-vs-object ambiguity
does the rest.
What actually breaks
SHA pinning was the industry answer to rug-pulls after SkillJacking / RepoJacking:
review commit aaa…, pin it, trust immutability. Plugin4Shell voids that
guarantee on the client.
Variant A (Claude Code, Codex, Copilot). Agent clones and runs
git checkout <40-hex-sha>. Attacker who controls the plugin repo
creates a branch named exactly like that SHA and makes it the default
branch. Git prefers the ref over the object when names collide (you get a quiet
“refname is ambiguous” warning). Working tree is malicious; the agent still reports
a successful install at the pin. Auto-update (default on Claude Code and Codex)
re-runs the same checkout when the marketplace bumps the pin — so already-installed
plugins flip without a prompt.
Variant B (Gemini CLI). Fetch the right commit into
FETCH_HEAD, then git checkout FETCH_HEAD. If the repo’s
default branch is itself named FETCH_HEAD, checkout resolves to the
branch and discards the fetched commit.
One client-side assertion closes both: after checkout, abort unless the resolved HEAD equals the pinned SHA. Marketplaces cannot fully enforce this — the pin is resolved inside the agent. Hosts help only partially: GitHub (and GitLab) reject 40-hex branch names; Bitbucket and self-hosted git often do not. Anthropic’s own docs still list Bitbucket / self-hosted as valid marketplace backends.
Patch status as of the disclosure window
- Claude Code — fixed in 2.1.179 (Anthropic confirmed Jun 17, 2026).
- Codex — fixed in 0.146.0 (“Verify Git plugin SHA checkouts”; Air verified Aug 12, 2026).
- GitHub Copilot — disclosed; no client patch shipped at disclosure. Treat auto-update as a live risk; inventory Git hosts behind every marketplace.
- Gemini CLI — deprecated; Google will not patch. Migrate (Air points at Antigravity, which has no marketplace SHA-pin path to bypass).
Private disclosure to all four was June 2026; public write-up mid-September. No CVE was assigned at disclosure — do not wait for a CVE number before inventorying.
Ops checklist for a production agent fleet
I care less about the PoC video and more about a two-column spreadsheet: agent version × Git host behind every marketplace plugin source.
- Version gate. Claude Code ≥ 2.1.179; Codex ≥ 0.146.0. Anything older is not “legacy,” it is unpatched RCE on plugin update.
-
Copilot path. Disable marketplace auto-update where you can
(
autoUpdate/COPILOT_AUTO_UPDATE=false). Prefer GitHub/GitLab-hosted marketplace repos (reject SHA-shaped refs). Treat Bitbucket and self-hosted plugin remotes as elevated risk until a client fix lands. - Gemini CLI. Do not keep it in the fleet for marketplace plugins. Migrate; do not “pin harder” on a client that will never ship the HEAD check.
- Assume plugin = code execution. Same blast-radius family as Muse Secure VM and OpenRouter shell: secrets stay at the boundary; agents never hold long-lived CRM/calendar passwords; network default-deny where you host sandboxes.
- Rotate after uncertain exposure. If engineers ran unpatched agents with auto-update on third-party plugins, rotate tokens those agents could see (GitHub PATs, cloud keys in env, MCP credentials).
- Marketplace inventory. List every plugin source: official vs community vs internal. Who can merge pin bumps? Who owns the upstream repos? Hijack of a trusted author’s repo plus Plugin4Shell is the zero-click path — SkillJacking already showed takeovers at scale.
Where this sits next to the rest of the stack
This month’s drafts keep circling the same production shape: cheap flash loops for interactive turns, sandboxed shell/Files for blast radius, Batch for overnight eval economics, credential surrogates so the agent never sees the password. Plugin4Shell is the distribution-layer sibling — the agent fleet’s plugin path is part of the trust boundary, not an IDE convenience.
OpenRouter weekly usage through Sep 22 still screams coding-agent volume on the apps side (Hermes / Claude Code / Kilo / Cline) while model volume sits on flash: GLM 5.3 Flash #1 (~18.4T, +61%), DeepSeek V4.1 Flash #2 (~17.8T, +122%), Hy4 preview #3 (~12.9T), GPT-5.6 Luna #4 (~8.67T), DeepSeek V4 Flash 0731 #5 (~8.64T). Those agents are exactly the class of tools Plugin4Shell targets. Ranking adoption without hardening the plugin checkout is how you buy more blast radius at a discount.
What I would do this week
- Force-minimum versions for Claude Code and Codex in the fleet image / brew pin / Nix flake — not a Slack reminder.
- Export the plugin list from every engineer machine that runs marketplace installs; flag non-GitHub/GitLab remotes.
- Turn Copilot marketplace auto-update off until Microsoft ships a HEAD-equals-pin check.
- Retire Gemini CLI marketplace use; document the migration target.
- Add “plugin SHA verify” to the same security review that already covers MCP and shell egress.
Doing the “right” thing — review, pin, install from a trusted marketplace — is exactly the posture Plugin4Shell defeats until the client asserts HEAD. Update the agent. Inventory the Git host. Assume auto-update is an attack surface, not a convenience flag. Say hello.
Related drafts: Muse Secure VM credentials, OpenRouter shell + Files API, OpenRouter Batch API, OpenRouter rankings in production, phone stack teardown.
Sources: Air Security — Plugin4Shell (Sep 17, 2026); CSA research note — Plugin4Shell; The Register coverage; OpenRouter rankings (usage through Sep 22, 2026).