夜雨聆风学习资料网

ARTICLE · 1073610

你装的 AI 编程助手,可能正在被别人远程执行代码

你装的 AI 编程助手,可能正在被别人远程执行代码

上周我照常打开电脑,终端里那个 AI 编程助手在后台自己更新了几个插件。

它一直是这样。默认开启,不需要我确认,也不用点任何东西。我一直以为这件事是安全的——因为插件的版本被"钉"在了一个 commit 哈希上:市场审核过那份代码,把哈希写进配置,此后的每一次安装和更新,都只会拉到那一个版本。

这是我理解里的标准答案。也是整个软件行业花了十几年才学会的做法。

直到我读完 9 月 17 日那份披露。

先说结论:四家里,两家已经不修了

漏洞叫Plugin4Shell,由安全公司 Air Security 披露。影响四个主流 AI 编程助手:Anthropic 的 Claude Code、OpenAI 的 Codex、微软的 GitHub Copilot、Google 的 Gemini CLI。

修复状态是这样的:

  • Claude Code:已在 2.1.179 修复
  • OpenAI Codex:已在 0.146.0 修复
  • GitHub Copilot:至今未发布补丁
  • Gemini CLI:产品已废弃,Google 确认不予修复,建议用户迁移

四个里,两个修了,两个没修。注意,不是"还没来得及"——从通报到公开披露,中间隔了三个多月。

还有一个细节值得留意:Claude Code 2.1.179 的发布说明里,并没有提到这次修复。修复这件事,是从 Air Security 的披露里才知道的。

少的是哪一行校验

先说清楚"钉版本"这件事为什么重要。

插件市场有一套标准流程:插件提交上来,人工评审,评审通过之后,把那个版本的 commit 哈希记下来(也就是 SHA pinning)。之后 agent 每次安装或更新,都按这个哈希去拉代码。

这套机制的用意是防"卷毯攻击"(Rug Pull)——插件作者可以在你信任他之后,悄悄把仓库里的代码换成恶意的。但只要你装的是那个被钉住的版本,换不换都影响不到你。

锚定的是哈希,哈希指向的是一个不可变的 commit 对象。这是整个信任链条的地基。

Air Security 发现的问题是:四个 agent 在检出(checkout)钉住的 commit 之后,没有一个去验证工作区里真正落地的代码,到底是不是那个 commit。

缺的就是一行校验——解析当前工作区的真实 HEAD,跟钉住的 SHA 对不上就中止。

就因为缺了这一行,Git 自身的一条既定行为变成了攻击通道。

Git 里有一条规则:当一个名字既是合法的引用(ref),又是对象 ID 时,git checkout 会优先解析为引用。它只往 stderr 打一条 refname is ambiguous 的警告——而在 agent 的自动化流程里,没有人会去看这条警告。

所以攻击方式就是:在插件的上游仓库里,建一个名字恰好等于那 40 位哈希的分支。

然后把它设为默认分支,内容指向恶意代码。

普通 git clone 会把默认分支拉成本地分支。等到 agent 执行 git checkout a1b2c3d4... 的时候,这个名字同时匹配一个本地分支和一个 commit 对象,Git 取了分支——恶意代码落地,而 agent 依然报告"已按钉住版本成功安装"。

而那个被钉住的 commit 本身,可以原封不动地留在仓库里。仓库历史看起来完全正常。

Gemini CLI 是另一个变体:它的流程是先 git fetch 拿到正确的 commit,再 git checkout FETCH_HEAD。攻击者只需要把默认分支命名为 FETCH_HEAD,刚取回来的正确 commit 就被静默丢弃了。

有个分界点值得一提:GitHub 会拒绝创建形似 commit 哈希的分支名,所以托管在 GitHub 上的插件不受第一个变体影响。但Bitbucket 和自建 Git 服务器允许这类名字——而这两个,恰恰是 Anthropic 官方文档里明确支持的插件市场后端。

为什么它是"零点击"的

很多远程代码执行漏洞需要骗你做一个动作:点开链接、装个插件、批准一个弹窗。

这个不需要。关键在于一个普遍存在的默认行为:Claude Code 和 Codex 里,已安装插件的后台自动更新是默认开启的。

这意味着攻击者不需要说服任何人装新东西。他只需要: 

  1. 提交一个真正无害的插件,通过评审,积累装机量
  2. 正常更新一次,市场把钉住的哈希挪到新 commit
  3. 在上游仓库建一个同名分支,指向恶意代码
  4. 哈希变更自动触发所有已安装 agent 的更新,检出拐向分支

受害者唯一"做错"的事,就是按照安全模型所期望的方式,正确地使用了一个受信任的市场。

而插件继承的是运行者的全部权限:本地源代码、云服务凭证、SSH 私钥、内部仓库、生产环境的访问通道。一次成功的利用,等于把开发者本人的数字身份整个交出去。

公平地说一句:截至披露日,没有分配 CVE 编号,也没有确认的野外利用案例。

三件事,今天就该做

第一步,查版本。Claude Code 升到 2.1.179 以上,Codex 升到 0.146.0 以上。Copilot 没有补丁可用,先别用非 GitHub 托管源的插件。Gemini CLI 建议直接迁走。

第二步,查插件来源。你的插件托管在哪?如果是 Bitbucket 或者自建 Git,那就在第一个变体的射程之内。

第三步,想清楚自动更新这件事。它是"零点击"的成因。补丁落地之前,可以考虑先关掉。

最后有一个容易忽略的点:披露信息里并没有说明升级会自动清理已被替换的插件。升级只挡住未来的偷换。如果你怀疑自己在攻击窗口内暴露过,稳妥的做法是升级之后,从可信来源把插件重装一遍。


这件事让我有点在意的,不是漏洞本身。

是那个缺失的校验实在太朴素了——朴素到你会以为"这不可能没人写"。但四个不同团队、四个不同代码库,同一个设计错误被复制了四遍。

安全圈有一句老话:审核一次代码,锁定它的哈希,此后永远运行这个被审核过的版本。这句话在过去十年里基本成立。

现在它多了一个前提:得有人低头确认过,落地的是哪一个。


一手出处

  • Air Security 研究实验室(Or Nevo、Dor Granat、Niv Hoffman),2026-09-17 公开披露
  • Cloud Security Alliance Labs 研究笔记:Plugin4Shell: SHA-Pinning Bypass Enables AI Coding Agent RCE
  • heise online:Critical flaw in Claude Code, OpenAI Codex, GitHub Copilot and Gemini CLI
  • 版本与时间线:Claude Code 2.1.179(2026-06-17 确认修复)/Codex 0.146.0(2026-08-12 验证修复)/Gemini CLI(2026-08-04 确认不予修复)

我排除了哪些数字

  • 网上流传的"影响上百万开发者""已被大规模利用"——没有信源支持。截至披露日无 CVE 编号、无野外利用确认,请不要引用这类说法。
  • 那 925 个被劫持 Skill、26,000 个受影响 agent 等数字来自 Air Security 此前的另一项研究(SkillJacking / RepoJacking),不是本次漏洞的数据,混用会出错。

相关学习资料