Plugin4Shell: Four AI coding agents trusted a pin they never verified

Plugin4Shell: Four AI coding agents trusted a pin they never verified

Pinning a plugin to a specific commit using its SHA hash is one of the main integrity safeguards in a software supply chain. Once that code has been reviewed and approved, the pin should ensure that this code, and nothing else, is what gets executed.

The problem is that "pinned" and "validated" are not the same thing. And a recent investigation demonstrated exactly that across four of the most widely used AI coding agents on the market.

What AIR Security found

Researchers at AIR Security identified a flaw in how plugins were pinned by SHA: the agent checked that the commit specified by the marketplace was pinned, but never verified that the checkout had actually landed on that commit.

An attacker who controls the repository of a legitimate plugin could exploit this gap to make the checkout resolve to malicious code while the pin still appeared to be respected. The result: zero-click remote code execution in Claude Code, Codex, GitHub Copilot, and Gemini CLI.

The mechanics vary by agent. In Claude Code, Codex, and GitHub Copilot, the issue involves a branch named exactly like the pinned 40-character commit hash. Because Git can resolve the branch name before the commit object, an attacker can create a branch with that exact name, set it as the default branch, and cause the agent to report a clean installation at the expected hash while actually executing different code.

This variant also depends on the Git host being used. GitHub, for example, restricts the creation of branches with 40-character hexadecimal names, while other hosts or Git servers may allow them.

Gemini CLI is affected by a different variant involving ambiguity in how FETCH_HEAD is resolved.

In agents where pinned plugins could be updated automatically, the attack could also execute without any new user interaction once the necessary conditions were in place. Hence the zero-click classification.

How each vendor responded

AIR Security publicly disclosed Plugin4Shell on September 17, 2026, after discovering the flaw in May, developing proof-of-concept exploits against all four agents, and subsequently notifying each vendor.

At the time of disclosure:

  • Anthropic had patched Claude Code in version 2.1.179.
  • OpenAI had fixed the issue in Codex 0.146.0.
  • Microsoft had not released a fix for GitHub Copilot. However, exploitation through 40-character branch names is restricted for repositories hosted directly on GitHub, although Copilot can use plugins hosted elsewhere.
  • Google did not plan to patch the affected version of Gemini CLI and was directing users toward Antigravity instead.

In other words, when the research became public, only two of the four agents had a patch available.

Why this matters beyond the patch

What makes this case interesting isn't just the list of companies involved.

It's that even an organization following the expected security model could still be exposed under certain conditions. A user could be running a plugin that had been reviewed and pinned exactly as the security mechanism intended, but if the repository ended up under an attacker's control, that pin did not necessarily guarantee that the approved code was what actually ran.

Doing everything right wasn't always enough.

Plugin4Shell exposes a simple but important distinction: checking that a security control exists is not the same as checking that it works.

The marketplace could review the code. It could record a SHA. It could require the plugin to be pinned. All of those controls could be correctly configured and the code that ultimately executed could still be different.

The problem wasn't the absence of a security control. It was assuming that the control produced the expected result without validating it.

And that distinction matters far beyond Plugin4Shell.

A configuration can be correct. A policy can be active. A control can appear to be properly implemented. But none of those things, on their own, demonstrate what happens when someone actually tries to break them.

Finding a security control is not the same as validating that it works under real-world attack conditions.

How many of your security controls are correctly configured but have never been validated under real-world attack conditions?

At Strike, we believe security doesn't end when a control is correctly configured. It starts when you can prove that it works as expected against a real attack.

Because "configured," "pinned," and "approved" describe intent. Validated describes a result.