SHA 锁定不等于验证:Plugin4Shell 与首个 AI 智能体供应链 RCE
925 个插件 skill 已被从原始维护者手中劫持,这些 skill 波及 134,000 个智能体。2026 年 9 月 17 日,AIR Security 披露了 Plugin4Shell — AI 智能体生态的首个供应链漏洞:一个零点击远程代码执行(RCE)漏洞同时影响 Claude Code、OpenAI Codex、GitHub Copilot 和 Google Gemini CLI,全部源于同一处缺失的检查。其机制是每个受影响智能体都跳过的一条 git 断言:智能体检出 marketplace 锁定的 commit SHA,却从不验证工作区真正落在该 commit 上。控制插件仓库的攻击者用锁定的 40 字符 SHA 命名一个分支,将其设为仓库默认分支,智能体便在报告"干净安装在锁定 commit"的同时安装了攻击者控制的代码(Cyber Security News;Help Net Security)。
这对任何针对生产系统运行编码智能体的团队都至关重要,因为锁(pinning)本身就是那个控制点。超越社区 marketplace 的组织 — 审查插件代码、将安装锁定到已审查的 commit — 一直依赖 SHA 锁定作为防护,而 Plugin4Shell 悄然使其失效:审查通过、锁定写入、运行的却是不同的代码(AIR)。本文覆盖一位工程负责人在下一次插件自动更新触发前需要了解的四件事:一条 git 命令讲清的机制、从良性采用到后台 RCE 的五步攻击、厂商响应记分板(两家已修复、一家未修复、一家弃用且未修复),以及为智能体安装的每个锁定工件 — 插件、MCP 服务器、skill — 封堵缺口所需的验证项。
关键要点
- 零点击 RCE 通过同一处缺失的 git 断言影响了全部四个主流编码智能体 — Claude Code、Codex、GitHub Copilot 和 Gemini CLI — AIR 于 2026 年 9 月 17 日披露 Plugin4Shell:智能体检出 marketplace 锁定的 commit SHA,却从不验证检出结果是否解析到了该 commit(AIR)。
- 925 个 skill 已被从维护者处劫持,波及 134,000 个智能体 — AIR 的 SkillJacking 研究;Plugin4Shell 击穿的正是为遏制此类仓库劫持而构建的 SHA 锁定机制(AIR)。
- Git 偏向与哈希同名的分支而非哈希本身 — 一条以锁定的 40 字符 SHA 为名、被设为仓库默认分支的分支,会把
git checkout <sha>重定向到攻击者代码;Gemini CLI 的变体则以FETCH_HEAD为攻击面(Cyber Security News)。 - 厂商记分板:2 家已修复、1 家未修复、1 家弃用且未修复 — Anthropic 在 2.1.179 修复了 Claude Code,OpenAI 在 0.146.0 修复了 Codex;Microsoft 尚未发布 Copilot 修复,Google 弃用 Gemini CLI 且未提供补丁,意味着所有现有安装持续暴露(Help Net Security)。
- 一条断言即可封堵两种变体:检出后验证解析出的 HEAD 是否等于锁定 SHA —
test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort— 且该检查必须在智能体内部运行,因为任何 marketplace 都无法强制执行一个它并不解析的锁定(AIR)。
下方图表将这次披露压缩为一分钟:五步攻击链、三天后的厂商记分板,以及封堵缺口的那条断言。
机制:一条断言,四个智能体
SHA 锁定本该按设计运转。审查者在某个 commit 上审查插件,marketplace 记录该 commit 的 SHA,智能体理应永远安装恰好是那段代码的版本。失败发生在最后一步。每个受影响智能体都会运行大致如下的序列(AIR):
git clone ./
git checkout aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # 锁定的 SHA 却从不追问检出是否真正落在锁定的 commit 上。这一 omission 之所以可利用,是因为 git 先解析名称后解析对象:当一个名称既是合法 ref 又是 commit 哈希时,git 偏向 ref,只打印一条 refname is ambiguous 警告。已经控制上游仓库的攻击者创建一个以精确的 40 位十六进制锁定 SHA 命名的分支,并将其设为仓库默认分支。一次普通的 git clone 会把该分支拉为本地 ref,git checkout <sha> 解析到该分支,工作区便被攻击者控制,而智能体报告"在锁定 SHA 上成功安装"(Cyber Security News)。
两个条件使这一手法成立。第一,没有任何普遍规则阻止"名为哈希的分支":git 自己的 check-ref-format 接受 40 位十六进制名称,虽然 GitHub 直接拒绝,但 Bitbucket 和自托管 git 服务器允许 — 而 Anthropic 自己的文档把 Bitbucket 与自托管 git 列为有效的 marketplace 后端(AIR)。第二,该分支必须是仓库默认分支;非默认分支只会以远程跟踪 ref 的形式到达,checkout 会退回真实 commit。
Gemini CLI 的失败方式不同。它的安装序列先抓取锁定的 commit,再检出 FETCH_HEAD:
git clone --depth 1 ./
git fetch origin 41d0bc0a4aeb2fbf797dacea39e876d98c95024b
git checkout FETCH_HEAD 如果仓库默认分支本身就叫 FETCH_HEAD,检出会解析到该分支并静默丢弃抓取的 commit(AIR)。命令不同,根因相同:智能体信任自己请求的名称,而不验证自己收到的 commit。
五步攻击:从采用到 RCE
两条攻击路径都不需要控制 marketplace。AIR 演示了两条:
- 埋点。 攻击者发布一个真正良性的插件,锁定在 commit
aaa…aaa。它通过审查。 - 采用。 用户安装。每次安装都锁定到已审查的 commit。
- 重新锁定。 攻击者推送一次仍然良性的例常更新;marketplace 把 pin 推进到
bbb…bbb。 - 变脸。 攻击者创建名为
bbb…bbb的分支,设为仓库默认分支,并指向恶意代码。被锁定的 commit 本身可以保持不动。 - 自动更新到 RCE。 变更后的 pin 触发所有智能体的后台自动更新 — Claude Code 与 Codex 的默认行为 — 检出解析到该分支,代码在无点击、无提示、无需重装的情况下运行(AIR)。
替代路径更快:接管合法维护者的仓库,直接跳过埋点步骤。AIR 的配套研究量化了其普遍性 — 925 个 skill 被从原始维护者处劫持,波及 134,000 个智能体(AIR)。这是一部三部曲的第三幕:The Story of Skills 展示了一个恶意 skill 波及 26,000 个智能体;MCPJacking 通过过期域名发现官方 marketplace 中 155 个可劫持的 MCP 服务器,研究者注册这些域名后,在每一个信任它们的智能体上获得了远程 prompt 执行能力(AIR)。Plugin4Shell 是行业为遏制这一切而构建的机制的边界失效。爆炸半径也大于智能体本身:插件与 add-on 继承运行智能体的开发者的权限 — 本地源代码、云凭证、SSH 密钥、内部仓库与生产系统(Cyber Security News)。
厂商记分板:两家已修复、一家未修复、一家弃用未修复
披露时间线显示协同披露起了作用 — 以及它止步于何处:
| 时间 | 事件 |
|---|---|
| 2026 年 5 月 | AIR 发现缺陷,对四个智能体均有可用的 PoC |
| 2026 年 6 月 | 对四家厂商的协同披露 |
| 2026-06-17 | Anthropic 确认在 Claude Code 2.1.179 中修复 |
| 2026-08-04 | Google 确认不会发布修复 — Gemini CLI 已弃用;用户被告知迁移到 Antigravity |
| 2026-08-12 | OpenAI 的 Codex 0.146.0 确认已修复 |
| 2026-09-17 | 公开披露 |
截至 9 月 18–19 日,记分板未变:Anthropic 已修复、OpenAI 已修复、Microsoft 尚未发布 Copilot 修复、Google 弃用 Gemini CLI 且未提供补丁 — 意味着所有现有 Gemini CLI 安装将持续暴露(Help Net Security)。GitHub 的应对 — 在其平台上禁用 SHA 形状的分支与标签名 — 并未封堵缺口,因为 marketplace 可以托管在 Bitbucket 或自托管 git 服务器上,这些名称在那里仍然合法(Cyber Security News)。
AIR 的总结最为诚实:"The fix has to ship in the agent, and updating is the only complete mitigation where one exists"(AIR)。其结构性原因值得为采购对话重述:pin 在智能体内部解析,因此 marketplace 无法强制执行它所宣传的保证。厂商侧的 marketplace 上传扫描(Anthropic 于 2026 年 8 月 6 日上线 Skill/Plugin Scanning)降低了恶意插件进入 marketplace 的概率,但无法替代智能体侧的检出验证 — 交换发生在审查之后、解析之时(MCP Security Hardening Checklist)。这也是治理层面的展示:四家厂商、一个共同的设计缺陷、一场持续三天的非对称响应 — 采购组织可以把它当作一家厂商安全补丁节奏的缩影来解读。
检出后验证:可泛化的控制
AIR 的一行修复可封堵两种变体(AIR):
test "$(git rev-parse HEAD)" = "" || abort 细节承载教训。git rev-parse HEAD 解析出工作区真正包含的内容 — 而非请求的名称。这一区分正是 Gemini FETCH_HEAD 变体得以溜过的地方。检查必须在智能体内部运行,因为 pin 在客户端解析。一个在检出后验证的 marketplace 只是在验证自己的记录;必须在解析不一致时中止的组件是智能体。
这一模式 — 在解析之后而非之前验证 — 可泛化到智能体技术栈中每一个锁定工件的控制。锁定的 MCP 服务器版本、锁定的 skill、锁定的模型权重、锁定的容器 digest:每一个都是"信任某个安装器会兑现、却无人验证其解析结果"的主张。同样的缺失断言存在于检出发生的每一处。本周需要落实的四项:
- 更新已有修复的智能体。 Claude Code 升级到 2.1.179 或更高;Codex 升级到 0.146.0 或更高。Copilot 与 Gemini CLI 没有修复 — 在补丁发布前限制这些智能体的可达范围(文件系统、凭证、网络出口),或遵循厂商的迁移路径。
- 盘点每一个锁定工件。 插件、skill、MCP 服务器版本、内部安装器。逐一确认是否存在跳过"解析后 HEAD"断言的代码路径 — 这包括团队自己写的内部工具,不只是厂商智能体。
- 审计插件仓库的劫持信号。 意外的分支变更、默认分支移动、所有权转移。925 个被劫持的 skill 在本次披露之前就已被夺走;仓库劫持是入口步骤,而且已经在规模化运作(Cyber Security News)。
- 把插件自动更新当作供应链交付通道,而非便利功能。 将智能体可拉取的 marketplace 与仓库列入允许清单;在智能体配置允许处,把重新锁定置于重新审查之下。零点击属性来自自动更新 — 去掉"零",攻击就需要用户动作。
两个相邻 CVE,以及持续暴露
同一周还出现了两个 MCP 服务器 CVE,与 Plugin4Shell 主题相同 — 信任被置于一个从未验证调用方的组件上。CVE-2026-54618 影响 0.2.0 之前的 Obsidian Web MCP:OAuth 授权端点向任何调用方发放授权码而不验证用户,使未经身份验证的远程攻击者获得对整个 vault 的完整读、写、搜索、移动、删除访问权限,已在 0.2.0 修复(Rapid7;GitHub advisory GHSA-hwhg-mrjc-8g43)。CVE-2026-54446 是 NetLicensing-MCP 中的缺失身份验证缺陷(CWE-306)(Practical DevSecOps)。它们叠加在数月未动的生态基线数字上:MCP 月下载量 97M+,抽样服务器中 82% 存在路径遍历漏洞,仅 8.5% 使用 OAuth(Practical DevSecOps)。
三项披露的规律在智能体技术栈的每一层相同:某个信任机制 — 一个 pin、一个 OAuth 流程、一个服务器端点 — 在错误的时间执行检查,或根本没有执行。Plugin4Shell 只是第一个一次性从单一产品跨越到整个生态的案例。
相关阅读
- MCP Security Hardening Checklist: 1,467 Exposed Servers and the Controls That Close Them — 本漏洞嵌入的 12 项控制基线:Plugin4Shell 属于供应链层(控制 5–7),紧邻 Skill/Plugin Scanning 更新
- Shadow AI Agents: 17,800 Add-Ons, 6.7 Million Installations, and the Runtime Control Gap — 决定被劫持 add-on 是否会被发现的清单与运行时控制缺口
- The First MCP CVE on the KEV List Hit Its Federal Deadline: LiteLLM and the Default-Key Vault — 达到联邦修复期限的 MCP CVE,以及封堵它的六项网关验证
一家中型工业分销商为内部工具运行 Claude Code,并部署了一个对 NetSuite 和两个供应商目录报价的采购智能体。团队清点了两条面上的每个锁定工件,把 Claude Code 升级到 2.1.179,禁用后台插件自动更新,并在自己的内部 MCP 模块安装器中加入解析后 HEAD 断言。插件来源移入两个已审查仓库的允许清单,审计跟踪记录每次重新锁定及其 diff。下一次 marketplace 事件变成一次版本升级和一次审查,而不是一次事件响应。
申请范围明确的构建。 一周 discovery。你将获得系统清单、工作流地图和固定范围 — 无论是否与我们合作构建。
想为您的系统构建这个吗?
这里的每份文档都来自真实的生产工作。如果您有目标系统和工作流想法,我们可以在一周内确定范围。
申请定制开发为期一周的发现阶段。您会拿到系统清单、工作流地图和固定范围——无论您最终是否与我们合作开发。