← Back to the cybersecurity blog

Plugin4Shell: the SHA pinning bypass in Claude Code, Codex, Copilot and Gemini CLI plugins

By Thilina Manana · COO, Director Técnico de Seguridad hard2bit y socio fundador · Published: 21 September 2026 · Updated: 21 September 2026
Plugin4Shell: the SHA pinning bypass

Whoever controls a plugin's repository needs only to create a default branch with the right name (the pinned commit's hash or, for Gemini CLI, FETCH_HEAD) and Claude Code, OpenAI Codex, GitHub Copilot and Gemini CLI will install something other than the reviewed plugin. Air Security calls the technique Plugin4Shell and published it on 17 September 2026 in a report by Or Nevo, Dor Granat and Niv Hoffman. Each of the four agents pins a plugin to a specific commit; each, the report says, took the checkout on trust and never confirmed that the working directory held that commit.

Anthropic (Claude Code 2.1.179) and OpenAI (Codex 0.146.0) fixed the flaw after the coordinated disclosure in June. Copilot remains unpatched and Gemini CLI, Google told Air, will stay that way. No CVE has been assigned, no vendor has published a security advisory and there is no sign of use in a real attack, according to checks by The Hacker News on 18 September.

What is Plugin4Shell and who is exposed?

Coding agents are extended with plugins: bundles of instructions, tools and execution hooks that are published in marketplaces and fetched by the agent from a git repository. For a review to count for anything, the marketplace records the hash of the reviewed commit, the forty-character identifier of that snapshot of the code, and the agent installs precisely that commit. It is the same idea as pinning a dependency by hash in a lockfile: the repository may change tomorrow, but the installation does not.

Plugin4Shell breaks that idea inside the agent itself. Nobody has to compromise the marketplace or persuade a developer to install anything new. The victim only needs a legitimate plugin, pinned to a reviewed commit, whose repository later falls into an attacker's hands. Air describes two ways of getting there: publish a harmless plugin, wait for it to be adopted and turn it malicious later, or take over the repository behind somebody else's plugin that the marketplace already trusts. As Help Net Security put it, the flaw catches people who had already done everything right: reviewed the plugin and pinned it.

The second route matches what the same firm described in August as MCPJacking: it found 155 entries in the official MCP server registry that pointed at expired domains, registered some of them and published a server of its own behind them, which agents accepted as the original. A plugin's repository is an asset that changes hands, lapses and gets bought, much like an npm package.

A branch named after a hash fools the checkout

The flaw combines two behaviours of git (it prefers a branch to a hash of the same name, and it allows branches of that shape) with one product decision: the agent never verifies which commit ended up on disk. The following summarises Air's technical analysis, which The Hacker News reproduced in a local test.

Claude Code, Codex and Copilot

All three clone the plugin repository and then run git checkout with the pinned hash. An attacker in control of the repository creates a branch named after the full hash of the pin and makes it the default. When the repository is cloned, that branch is created locally as well. When the agent asks for a checkout of the hash, git finds a branch with exactly that name, prefers it over the object identifier and at most prints a warning that the name is ambiguous. The reviewed commit may sit untouched in the repository; what remains on disk is whatever the branch points to.

OpenAI's public fix describes the same behaviour: git can interpret a requested commit hash as a branch name and materialise a different commit from the one that was pinned.

Git's name check accepts strings of forty hexadecimal characters. Some hosts forbid them: GitHub rejects branches and tags that resemble a hash, a spokesperson confirmed to The Register. Bitbucket and self-hosted git servers accept them, Air says, and both, again according to Air, appear among the hosts that Claude Code's documentation permits for a marketplace.

Gemini CLI

Gemini CLI does not check out the hash directly. It clones at depth one, fetches the pin with git fetch and then checks out FETCH_HEAD, the name under which git remembers whatever it last fetched. If the repository's default branch is itself called FETCH_HEAD, the checkout resolves to the branch and the commit that was just fetched is discarded. Since FETCH_HEAD does not look like a hash, The Hacker News notes that GitHub's naming rule does not clearly block this variant.

Auto-update removes the need for any user interaction

The problem would be confined to installation time if the agent fetched a plugin only once. Claude Code and Codex update installed plugins in the background, the report says, and that is where the absence of interaction comes from: when the marketplace moves the pin, both agents repeat the checkout and the substituted code reaches plugins that were already installed and in use.

The attacker never has to get anything malicious past the marketplace's review: they ship a harmless version, get it pinned and only then create the hash-named branch; every agent that updates from that moment on receives the malicious code.

There is a nuance Air does not stress and the same publication does, after reading Anthropic's and GitHub's documentation: auto-update is enabled by default only for each agent's official marketplaces, which are hosted on GitHub, and is off or optional for outside ones. On 18 September it also checked that every plugin in Anthropic's community catalogue and in the default catalogues for Claude Code and Copilot points to a GitHub repository.

Anyone who installs only from those catalogues is not exposed to the hash-named-branch variant. The exposure lies in internal or third-party marketplaces hosted outside GitHub, precisely the ones a company sets up to control what its developers install.

The missing check fits in one line: after the checkout, resolve the commit in the working directory and abort unless it equals the pin. It has to inspect the resolved HEAD, because the Gemini variant requests a reference, FETCH_HEAD, that is not what ends up on disk. And it has to run in the client, since the client is where the hash is resolved.

What has changed since last year?

Research on agent security had so far concentrated on the model and on the agent itself, in Air's framing; on this blog we saw it with poisoned observability logs turned into instructions. Plugin4Shell goes after the distribution layer underneath, the catalogues through which plugins reach developers' machines.

That layer has enough reach to interest an attacker. Air cites its own earlier research: a test skill (the lighter form of agent extension) that the firm published reached more than 26,000 agents by changing an external link once review had cleared it, and 925 skills already in use could be hijacked by taking over their maintainers' repositories. Those are figures from a single vendor with a product in this market, although the first of them had independent coverage in June.

The target is the same as in this year's npm incidents: the Mini Shai-Hulud worm, which plants execution hooks in Claude Code and VS Code, and the compromised jscrambler package, which stole AI tooling credentials, went after what a substituted plugin goes after. The industry's answer to repository takeovers was pinning by hash. Four implementations with the same gap point, in our reading, to a badly specified control: the rule said "pin the commit", not "check you got there".

The marketplace cannot fix it

The hash is resolved on the client, so no marketplace can deliver on its own what it promises. It can blunt the damage by refusing git hosts that allow hash-shaped branch names, which on what has been published leaves little beyond GitHub, but that excludes hosts the agents officially support and does nothing about the Gemini variant. Code review at the marketplace does not help either: the reviewed commit is still intact, and the agent never reaches it.

The second problem is the privilege the plugin runs with. A coding agent works with the developer's git credentials, cloud tokens, API keys and access to every repository the developer can clone. In our experience those credentials often belong to non-human identities, service accounts and tokens with more permissions than the developer, no expiry and no inventory, and a substituted plugin inherits them at update time without passing through email or the browser.

Which agents are patched and which are not?

Air's timeline, completed with what the press has published, leaves each vendor at a different stage:

  • May 2026: Air finds the flaw and builds proof-of-concept exploits against all four agents.
  • June: coordinated disclosure to the four vendors. On 17 June Anthropic confirms to Air the fix in Claude Code 2.1.179; the release notes for that version do not mention it, so the record is Air's.
  • 4 August: Google tells Air that no patch will ship because Gemini CLI is being deprecated.
  • 12 August: Air verifies the fix in Codex 0.146.0, whose public pull request describes the bug.
  • 17 September: publication. Microsoft has released no fix for Copilot; it had not responded to The Register when that article went out and, Air says, has not answered the June disclosure either.

There is an unresolved dispute over Copilot. GitHub, which belongs to Microsoft, did respond to The Register and maintains that the attack cannot work against repositories hosted on GitHub because of its naming filter. Air counters that Copilot accepts marketplaces on other hosts and remains exposed there.

On Gemini CLI, Google holds two positions in tension. Its May announcement retired the tool in favour of Antigravity CLI, cut off consumer accounts on 18 June and promised enterprise customers continued support and updates. In August, according to Air, it said no patch would ship. There is no public clarification on whether those enterprise updates will include this flaw.

Controls that still work

The ones that treat agents as what they are: third-party software with privileged access. That brings them into the third-party risk programme, under the same discipline as any other link in the software supply chain.

  • Keep an inventory of agents and versions on developers' machines. Claude Code below 2.1.179, Codex below 0.146.0 and Copilot, with no fixed version, are vulnerable when pointed at marketplaces outside GitHub; Gemini CLI is vulnerable regardless of host, because its variant does not depend on the hash's name.
  • Set a policy on permitted marketplaces. An internal marketplace hosted on GitHub, or on a server that rejects hash-shaped branch names, limits the first mechanism; take it as read that it does not close the second. If the internal marketplace lives on Bitbucket or on a git server of your own, that is the case that matters most.
  • Switch off plugin auto-update on managed machines, where the feature exists, and update by hand after reviewing the commit change. Developers will find it a nuisance, but background updating is the step that removes user interaction.
  • Scope the credentials the agent runs with: short-lived git tokens, no cloud credentials in the agent's session, and a container or virtual machine for projects that install third-party plugins. Measuring that privilege is where an AI agent and MCP security audit should start.
  • Have EDR watch agent processes: git clones the agent starts to domains other than the one hosting the approved marketplace, unexpected child processes after a plugin update, and writes outside the plugin directory. A threat-hunting team can turn those into three queries.
  • Anyone maintaining a marketplace of their own has one periodic check, listing the branches of every plugin repository and alerting on any name that is forty hexadecimal characters long or is exactly FETCH_HEAD, and one permanent change to the installer: compare the commit resolved after checkout with the pin.

Reviewing and pinning are not enough unless the installer verifies the result. And MCP and agent security in production has to cover the plugin distribution layer alongside the server and the model.

What is still unknown

No CVE identifier has been assigned that would let the case be followed in the usual vulnerability databases. Nor is there a public list of affected catalogues, because the flaw does not live in any of them. The dispute between GitHub and Air over Copilot is still open, Microsoft has not commented, and no source says whether updating the agent removes a plugin that was already swapped or only prevents future swaps. A good starting point is to count how many internal installers in the organisation pin a hash and how many verify the commit they install.

The configurations and checks described are a starting point and should be validated in a test environment before being applied in production. Details of the flaw, its variants and the state of fixes come from Air Security, from the checks published by The Hacker News and The Register and from Google's and OpenAI's public announcements. They reflect what was known on 21 September 2026. Naming the affected products implies no judgement on their overall security, and patch status may change.

Frequently asked questions

Does Plugin4Shell have a CVE number or a CISA KEV entry?

As of 21 September 2026 there is no CVE identifier and no KEV entry, and The Hacker News found no vendor security advisory and no sign of use in a real attack. That makes it awkward for the usual vulnerability management tooling, which sorts by CVE: the flaw has to be tracked by the agent version installed on each machine.

Is updating the agent enough to be protected?

Updating Claude Code to 2.1.179 or later and Codex to 0.146.0 or later closes the flaw, according to Air, but no source says whether the update removes a plugin that was already swapped or only prevents future swaps. To be safe, review the installed plugins after updating and reinstall them from the pinned commit. Copilot and Gemini CLI have no fixed version, which leaves only the mitigations: restricting marketplaces, disabling auto-update where it exists and scoping credentials.

If my plugins are hosted on GitHub, am I protected?

Largely. GitHub rejects branch and tag names shaped like a hash, which blocks the mechanism affecting Claude Code, Codex and Copilot for repositories hosted there; the default marketplaces of those agents point to GitHub, as The Hacker News checked. It does not cover the Gemini CLI variant, which relies on a branch called FETCH_HEAD, and it does not protect internal or third-party marketplaces hosted on Bitbucket or self-hosted git servers.

How can I tell whether an installed plugin has already been swapped?

Compare the commit actually present in the plugin directory with the hash the marketplace pins: if they differ, the plugin is not the reviewed one. Also list the branches of the remote repository and look for a branch name that is forty hexadecimal characters long or exactly FETCH_HEAD, and check when the last background update ran. Treat a mismatch as an incident: isolate the machine and rotate every credential the agent could reach.

How is this different from an attack on npm or PyPI?

On npm or PyPI the malicious release is a new version served by the registry, and a lockfile with hashes catches it. In Plugin4Shell the pinned identifier stays the same and it is git, on the client, that resolves it to different code. The marketplace's lockfile still looks correct, and the defence that closes the flaw is an installer that verifies the resulting commit, not the requested one.

Can a marketplace fix Plugin4Shell on its own?

Not fully. Only the agent can check where the checkout ended up, so the complete fix has to come from each vendor. What a marketplace can do is restrict the permitted hosts, and that restriction does not reach the Gemini CLI variant.

Why should a CISO care about a flaw in developer tooling?

Because a substituted plugin runs with the developer's identity and inherits their credentials at update time, from a tool that usually sits outside the third-party software inventory and outside the email and browser controls. The risk is governed like that of any supplier with privileged access.

What about Gemini CLI installations inside enterprises?

They keep working under an enterprise licence or an API key. Google promised those customers support and updates in May, but according to Air it said in August that this flaw will not be fixed, and there is no public clarification. The realistic options are migrating to Antigravity, which according to Air has no plugin commit pinning to bypass, or scoping the agent's permissions and restricting its marketplaces in the meantime.

Want to know what's actually exposed, and what to fix first?

Thirty minutes with a technical consultant — not a salesperson — is enough to get the problem in order: what's exposed right now, what gets fixed this week, what can wait, and what each stage costs. Penetration testing, security audits, vulnerability management, Microsoft 365, SOC/MDR and incident response.

If your situation is different, tell us anyway — we also take one-off questions on cybersecurity and regulatory compliance.

Based in Spain · Working across the EU and LATAM · ENS High · ISO 27001 · We usually reply in under 24 business hours