A Trust Boundary Hidden in Plain Sight
AI coding-agent marketplaces use commit pins to answer a critical question: is the plugin being installed the same code that was reviewed? Plugin4Shell showed that four leading clients could answer yes without checking the final result.
The name, coined by AIR Security, covers related commit-verification failures in Anthropic Claude Code, OpenAI Codex, GitHub Copilot CLI, and Google Gemini CLI. Each client requested a pinned Git commit but failed to confirm that the installed working tree actually resolved to it. With control of an accepted plugin repository, an attacker could substitute different code while the marketplace continued to display the approved pin.
That breaks more than one checkout command. It breaks the trust decision made by reviewers, marketplace operators, administrators, and developers who rely on an immutable commit as the boundary between approved and unapproved code.
AIR reported functional proofs of concept against all four clients. OpenAI’s public fix and regression test independently confirm the main failure mode in Codex. No evidence of exploitation in the wild was identified through the September 20, 2026 research cutoff, and no public CVE or authoritative CVSS score was available.
At a Glance
| Question | Answer |
|---|---|
| What failed? | Clients did not verify that the installed Git HEAD matched the marketplace’s commit pin |
| What could an attacker do? | Substitute plugin content that runs with the coding agent’s effective permissions |
| What must the attacker have? | Control of an accepted plugin repository and a compatible Git host |
| Is it always zero-click? | No; automatic updates and prior plugin adoption are required |
| Was exploitation observed? | No public evidence was identified through September 20, 2026 |
| Is there a CVE? | No canonical CVE was identified |
| What is fixed? | Claude Code 2.1.179 and Codex 0.146.0 are the documented fixed versions |
| What remains unresolved? | GitHub Copilot CLI and enterprise Gemini CLI remediation status |
The exposure is serious but conditional. A victim must use an affected client with a Git-backed plugin source, the Git host must permit the relevant conflicting ref name, and an installation or update must reach the attacker-controlled repository. Those conditions matter when prioritizing response, but they do not restore the integrity guarantee that commit pinning was supposed to provide.
How the Pinning Bypass Works
A full Git commit hash is meant to identify one immutable object. The affected
clients passed that value to Git during plugin materialization but did not
verify the commit that became the working-tree HEAD.
Git accepts several kinds of names when resolving a revision. Under the conditions described by AIR, a conflicting ref could take precedence over the intended object. The checkout command could succeed even though the resulting working tree came from a different commit.
[!IMPORTANT] A successful checkout is not proof that the requested commit became the working tree. The client must compare the resolved
HEADwith the approved commit and fail closed when they differ.
At a conceptual level, the substitution follows this sequence:
- A marketplace reviews plugin content and records its full commit hash.
- Users install the approved plugin from its Git repository.
- An attacker later gains or already holds control of that repository.
- The attacker introduces a conflicting default ref accepted by the Git host.
- The client resolves that ref instead of the intended object during install or update.
- Because the client never compares the resulting
HEADwith the pin, the substituted plugin content is accepted and can run.
The marketplace record does not need to change during the final substitution. That is why the flaw defeats a review process built around immutable pins.
Two Related Variants
AIR documented two paths to the wrong code:
- Claude Code, Codex, and GitHub Copilot CLI could resolve a 40-character SHA-shaped default branch instead of the intended commit object.
- Gemini CLI could resolve a default branch named
FETCH_HEADinstead of the metadata file containing the fetched commit.
Both paths violate the same security invariant, but a mitigation for one does
not automatically stop the other. GitHub rejects branch and tag names that
look like 40-character object IDs, which constrains the first path for
GitHub-hosted plugin repositories. That restriction does not establish
protection against Gemini CLI’s separate FETCH_HEAD path.
OpenAI’s Codex correction
captures the durable fix: resolve HEAD after checkout and reject the plugin
source unless it exactly matches the requested SHA. Its regression test uses a
default branch named after another commit’s hash and verifies that the mismatch
is rejected.
Why Zero-Click Is Conditional
AIR described Plugin4Shell as zero-click remote code execution. That label fits a specific deployment state: a user already trusts and has installed a plugin, the client automatically updates it, and an attacker controls the upstream repository when the update occurs.
It is not a universal property of every installation. Initial plugin adoption
still requires a user or administrator trust decision. Update behavior also
varies. The
Copilot CLI plugin reference
states that first-party plugins update at session start, while a third-party
marketplace must opt in with autoUpdate: true. AIR reports automatic updates
as the default in Claude Code and Codex.
The attacker also needs repository control, whether as the plugin publisher or through a separate compromise. Plugin4Shell does not itself provide that access. It defeats the commit pin that is supposed to contain the damage after repository ownership becomes malicious.
Product Status
| Product | Affected range | Status at the research cutoff |
|---|---|---|
| Claude Code | Lower bound unknown; before 2.1.179 | AIR reports version 2.1.179 fixed the flaw |
| OpenAI Codex | Lower bound unknown; before 0.146.0 | Version 0.146.0 contains the public verification fix |
| GitHub Copilot CLI | Exact range unknown | AIR reported no fix; no public fixed version found |
| Gemini CLI | Exact range unknown | Consumer migration advised; enterprise status unclear |
Anthropic released Claude Code 2.1.179 on June 17, 2026. AIR says this release fixed Plugin4Shell, although Anthropic’s public notes do not identify the security change.
OpenAI merged commit identity verification on July 22, 2026. The change appears in the changelog for Codex 0.146.0, released July 29, 2026.
AIR reported no GitHub Copilot CLI fix by public disclosure on September 17. No reviewed Microsoft advisory or documentation identified a fixed version by the research cutoff.
AIR also reported that Google would not patch consumer Gemini CLI and advised migration to Antigravity CLI. Google’s transition announcement confirms that consumer service moved to Antigravity CLI, but it also states that Standard and Enterprise customers retain Gemini CLI access and updates. The Plugin4Shell remediation status of those enterprise deployments remains unresolved.
What Is the Real Impact
AIR reported execution of substituted plugin content across all four tested clients. That content runs within the coding agent or plugin execution context. The resulting impact depends on the permissions, sandbox, tools, and credentials available to that process.
Plausible consequences include access to source code and local files, theft of development or cloud credentials, execution of plugin hooks or Model Context Protocol servers, modification of build output, and access to downstream systems through available credentials.
Full-host compromise is possible only where the execution context provides the necessary access. It is not an automatic result in every deployment. The risk is highest when unpatched clients use non-GitHub or self-hosted plugin sources, automatic updates, and broadly privileged agent processes.
No CVE Program, CNA, NVD, or vendor record had assigned a CVE to Plugin4Shell by September 20, 2026. No authoritative CVSS vector or vendor-assigned CWE was identified. CWE-494, Download of Code Without Integrity Check, is a reasonable analytical mapping, not an official assignment.
What Defenders Should Do
Patch and Contain
- Upgrade Claude Code to version 2.1.179 or later.
- Upgrade OpenAI Codex to version 0.146.0 or later.
- Request explicit Microsoft guidance before treating a GitHub Copilot CLI version as fixed.
- Migrate consumer Gemini CLI deployments to Antigravity CLI.
- Request explicit Google guidance for Standard, Enterprise, and API-key Gemini CLI deployments.
- Disable automatic plugin updates where a fixed client is not confirmed.
- Disable or uninstall plugins that are not required.
Reduce Supply-Chain Exposure
- Inventory installed plugins, marketplace sources, commit pins, client versions, and update settings.
- Restrict plugin sources to approved repositories or immutable internal mirrors.
- Run coding agents with least privilege and isolate them from production credentials.
- Review plugin hooks, executable content, and MCP server definitions before approval.
- Verify the resolved commit after every install and update.
A GitHub-only repository policy constrains the SHA-shaped-branch variant, but it does not resolve Gemini CLI’s reported path. Source restrictions are useful compensating controls, not substitutes for client-side verification.
Investigate Existing Installations
Public sources do not establish whether upgrading automatically removes or
revalidates previously substituted plugin caches. Preserve suspicious caches
for investigation, compare installed plugin HEAD values with trusted
marketplace pins, and reinstall approved plugins after patching.
Detection and Hunting Ideas
These ideas are hypotheses, not validated detections. Test them against the client versions, paths, schemas, and normal update behavior in your environment.
Find Exposed Clients
Inventory endpoints for affected client versions, installed plugins, Git-backed marketplace URLs, automatic-update settings, and expected pins. Required data includes software inventory plus plugin configuration and cache metadata.
Compare the Pin With What Was Installed
For each Git-backed plugin, compare the resolved installed HEAD with the full
commit hash in the marketplace manifest. A mismatch is a high-value finding,
but collection logic should first be validated against known-good and patched
clients.
Monitor Repository Ref Changes
Review approved non-GitHub repositories for 40-character hexadecimal default
branches or a default branch named FETCH_HEAD. Git server audit logs,
repository API snapshots, and default-branch history can support this check.
These names are risk signals, not proof of compromise.
Correlate Installation With Execution
Correlate coding-agent processes that clone, fetch, or check out plugin sources with new scripts, executables, hooks, or MCP servers launched from plugin cache directories. Useful telemetry includes process creation, command lines, file writes, network connections, and DNS activity.
No well-sourced malicious domains, IP addresses, URLs, file hashes, repository names, or payload identifiers were published. Values shown in research examples are synthetic and should not be treated as indicators of compromise.
The Larger Lesson
Plugin4Shell is a reminder that declaring an immutable identifier is not the same as enforcing one. A security control built around a commit pin succeeds only when the consumer verifies the object that reaches the execution boundary.
That distinction becomes more important as coding agents gain access to source repositories, local files, credentials, build systems, and external tools. Plugin trust is transitive: users trust a marketplace, the marketplace trusts a repository and commit, and the client must preserve that decision during every install and update. One missing comparison can invalidate the entire chain.
For defenders, the immediate work is concrete: identify the clients and plugins in use, patch where fixes are documented, constrain unresolved deployments, and verify installed content rather than relying on configuration alone. For vendors, the standard is equally direct: resolve the final artifact identity and fail closed when it differs from what was approved.
Research Notes
This article covers public information available through September 20, 2026. It does not claim independent reproduction, observed exploitation, or validated detection coverage. AIR’s functional proofs of concept are reported findings; OpenAI’s public correction provides direct implementation evidence for Codex.
No canonical CVE, complete affected-version ranges, official CVSS score, or confirmed exploitation in the wild was identified. Anthropic’s public release notes do not name the fix, Microsoft remediation was unresolved, and enterprise Gemini CLI status remained unclear at the cutoff.
Sources
All sources were accessed on September 20, 2026.
- AIR Security, Plugin4Shell, published September 17, 2026.
- OpenAI, Verify Git plugin SHA checkouts, merged July 22, 2026.
- OpenAI, Codex 0.146.0, released July 29, 2026.
- Anthropic, Claude Code 2.1.179, released June 17, 2026.
- Google for Developers, Transitioning Gemini CLI to Antigravity CLI, published May 19, 2026.
- GitHub, GitHub Copilot CLI plugin reference, no publication date available.
- GitHub, Dealing with special characters in branch and tag names, no publication date available.
- CVE Program search results for Plugin4Shell, no publication date available.
- The Hacker News, Plugin4Shell Lets Repository Owners Swap Pinned Plugin Code Across Four AI Coding Agents, published September 18, 2026.
- MITRE, CWE-494: Download of Code Without Integrity Check, updated April 30, 2026.