flawopen.com/AI Security/plugin4shell-ai-agent-plugin-sha-pin-bypass
Plugin4Shell: AI-Agent Plugin SHA Bypass
Four AI-agent plugin installers fetched pinned Git revisions but skipped commit verification. Plugin4Shell exposed the gap; check the resolved SHA.[1]
A library reserves a particular book edition by its unique catalog number. The clerk asks for that number but accepts a different book when a shelf label happens to use the same text. A SHA pin is the catalog number; the installer must inspect the checked-out commit itself before trusting or running the plugin.[1]
Core Concepts & Subsystem Terms
Commit SHA- A hash identifying a specific Git commit object. A secure pinning workflow must verify the resolved checkout against this value.[1], [2]
Git ref ambiguity- Git accepts both object IDs and names such as branches as revision expressions. Where a name can resolve as a ref, a request that looks like a commit ID may select that ref instead.[1]
Plugin marketplace- A catalog that distributes agent extensions and may record a reviewed plugin revision. The installing client still has to enforce the pin.[1]
CWE-345- Insufficient Verification of Data Authenticity: a system uses data without adequately checking that it is the expected authentic value.[5]
Framework mappings
- CWE reference for the weakness described in this guide: CWE-345
Step-by-Step Attack Flow
A marketplace records a reviewed commit
A plugin entry points to a repository and a specific commit SHA that reviewers expect the installer to use.[1]
The repository owner can change refs
AIR Security reports that a repository controller can create a default branch whose name matches a requested SHA on Git hosts that permit such names. It describes a separate FETCH_HEAD ref-resolution path for Gemini CLI.[1]
Source Code: Flaw vs. Secure Implementation
The vulnerable path conflated a successful name resolution with proof of object identity. The patch checks the resulting HEAD against the marketplace pin and refuses to materialize a different commit. This code pair reflects the Codex patch; the other products had distinct installer implementations and must not be assumed to share this exact fix.[2], [6]
// Pre-fix shape from OpenAI Codex PR #34644
if let Some(target) = sha.or(ref_name) {
run_git(&["checkout", target], Some(destination))?;
}
// A successful checkout was treated as proof that a SHA pin matched.
// Codex fix: verify the resolved commit, not only the requested argument
if let Some(sha) = sha {
run_git(&["checkout", sha], Some(destination))?;
let checked_out_sha =
run_git_output(&["rev-parse", "HEAD"], Some(destination))?;
if !checked_out_sha.eq_ignore_ascii_case(sha) {
return Err(format!(
"checked out Git SHA {checked_out_sha} does not match requested SHA {sha}"
));
}
} else if let Some(ref_name) = ref_name {
run_git(&["checkout", ref_name], Some(destination))?;
}
Engineering & System Hardening Checklist
- ✓After every SHA-pinned checkout, resolve the materialized commit (for example, <code>git rev-parse HEAD</code>) and compare it exactly with the requested pin before loading plugin files.[2], [6]
- ✓FlawOpen implementation recommendation: Fail closed on a mismatch, missing HEAD, command error, or unexpected revision format; do not fall back to a branch name.[2]
- ✓Test the installer with a temporary local repository where a default branch name collides with a different commit's SHA; assert that materialization is rejected and no plugin code is loaded.[6]
- ✓FlawOpen implementation recommendation: Keep ref-name installs distinct from immutable SHA pins in types and control flow, and record the verified commit in installation metadata.[1]
- ✓Inventory affected agent versions and marketplace Git hosts. GitHub blocks SHA-shaped branch names, but that host-specific rule does not protect installations using other supported hosts or Gemini's separately reported FETCH_HEAD path.[1], [4]
- ✓The cited AIR disclosure reports Codex fixed in 0.146.0 and Claude Code in 2.1.179, but does not give complete affected-version ranges. Verify current vendor guidance for Copilot and Gemini CLI before recommending a status or action.[1], [3], [7]
- ✓Retain Codex’s regression test
materialize_git_source_rejects_sha_that_resolves_to_hostile_default_branch; it builds a temporary local repository and asserts that a mismatched HEAD is rejected before the plugin source is materialized.[6]
Sources
- AIR Security: Plugin4Shell disclosure and coordinated vendor status
- OpenAI Codex PR #34644: Verify Git plugin SHA checkouts
- OpenAI Codex 0.146.0 release
- The Hacker News: independent reporting and host-specific exposure caveats
- MITRE CWE-345: Insufficient Verification of Data Authenticity
- Codex regression test: reject SHA resolving to hostile default branch
- Anthropic Claude Code v2.1.179 release