Featured image of post Claude Code 官方扩展被投毒:IDE 插件市场正成为 Agent 供应链的新前线

Claude Code 官方扩展被投毒:IDE 插件市场正成为 Agent 供应链的新前线

先说这次跟今年前几起 AI 供应链事件最不一样的一点:没有冒充可识别。

以往这类攻击你还能靠三个动作发现:看包名像不像正品、对一下源码或 Git tag、确认发布者是不是官方。这次三个动作全部失效。攻击者用的是 Anthropic 的官方扩展、官方发布者身份 anthropic.claude-code、正常的版本号递增,被替换的是真东西。

Manifold Security 的研究负责人 Ax Sharma 那句话把这个性质说得比谁都清楚:这次没有冒充可以识别,那就是 Cursor 自己市场里的官方 Claude Code 扩展,一个被污染的上架条目把 SSH 后门推给了最多 5,000 名用户。他还补了一句我认为是全文最关键的趋势判断,查发布者名字在发布者本身就是真的时帮不上忙,能帮上忙的是盯行为。

先把事实摆清

10 月 29 日,Cursor 的 VS Code 扩展市场里出现了一个被篡改的 Claude Code 扩展。窗口期是太平洋时间凌晨 2:27 到下午 1:35,大约 11 小时。受影响的版本号是 2.1.312 和 2.1.313,Cursor 的公告最初只提了 313,后来把 312 一并纳入。装机量上限是 5,000 名用户,Cursor 说会逐个联系他们。

载荷是在扩展的 extension.js 里前置的一段立即执行函数(IIFE),被塞在压缩后的扩展包最前面。它就做一件事:Node 一加载这个文件就执行,早于扩展自己的 activate 回调跑起来,用户完全不需要跟 Claude Code 交互。

macOS 安全公司 Phorion 发现并披露了这个包,OpenSourceMalware 同步跟进。Cursor 的处置是下架、关停整个市场做审计、确认没有别的扩展被同样手法改过、轮换自己的密钥、重建市场再上线,并联合托管商把攻击者的服务器下线。Anthropic 随后发布了干净版本 2.1.314。

哪些是事实,哪些还不清楚

这篇稿子有一节必须单独写,因为这个事件里被引用最广的几个说法,可靠程度并不一样。同时这也是标题需要打折的地方。

属于事实的部分:恶意版本由 Cursor 的市场分发,后来确认这是唯一的分发源;Cursor 在公告里明确写了这些恶意版本不是 Anthropic 开发的;Anthropic 的两名员工(Felix Rieseberg 与负责安全的 David Dworken)公开否认自家系统或员工电脑被攻破,Rieseberg 的说法是有人拿到了 Cursor 市场的访问权限,发布了一个被篡改的副本,而那个副本不是他们构建或发布的;攻击者的服务器已经停止工作。

还不清楚的部分更重要:恶意版本究竟是怎么进到市场的。Cursor 到现在没有解释这一步。BleepingComputer 把这个未解问题写得很直白,攻击者如何以 Anthropic 的名义在 Cursor 市场发布扩展,以及 Cursor 或 Anthropic 的系统是否在这个过程中被攻破,都还没有答案。

另外还有一处报道打架,值得读者知道。Phorion 说的是他们在 Open VSX 上发现了这个恶意包,但后来的报道确认 Cursor 是唯一分发源,而 Sharma 公开反驳了「Open VSX 版本也被污染」的说法。初始发现位置与实际分发位置,在报道里没有完全对齐。

最后是标题那一句。「官方扩展被投毒」在窄义上成立,因为被篡改的确实是官方扩展的构建;但如果读成「Anthropic 的官方发布被投毒」,那就错了。被污染的是第三方市场的上架条目,Anthropic 的官方分发链路没有受影响,他们也已经把干净版本发出来了。这个区别决定了读者该找谁负责,所以我在正文里保留这个限定。

前置一段 IIFE,意味着它不需要理解扩展

载荷的结构比内容更值得注意。它没有改扩展的逻辑,只是在压缩包最前面插了一段代码,导入 child_process、fs、os、path、http、crypto 这些标准模块,然后就跑了。

这个做法说明攻击者不需要读懂 Claude Code 是怎么实现的。任何插件,只要发布位被拿下,都可以被这样在前面加一段。插件本身写得安不安全,跟它会不会被这样改写是两件事。这也解释了 Cursor 的反应为什么是关掉整个市场而不是下架一个包:出问题的地方在上架这个动作本身可不可靠,跟单个包写得安不安全无关。

顺带一个架构层面的细节,它让这件事更值得担心。微软的官方市场条款限制它只能服务微软自己的产品,所以基于 VS Code 开源代码做的编辑器(Cursor、Windsurf 这类)得靠别的市场,Open VSX 或者自建市场。分发路径比大多数人以为的要分散,而每一个都是独立的信任点。

名单本身就是情报

载荷偷的东西里,有一项值得单独说:它上报了最多 40 个「看起来像密钥、token、密码、AWS 或 GCP 凭据」的环境变量名字。值留在本机。

Phorion 的 CEO Calum Hall 对这个设计的解读是,这份名单给了操作者一份清单,告诉他哪些主机握着什么凭据、该先打哪一台。这句话要点出来,因为它意味着这次外泄的资产是「目标排序」,而不是凭据本身。对攻击者来说,知道哪台机器值钱,比一次性捞走一堆可能过期的字符串更有用。

载荷还上报主机名、用户名、操作系统、架构、家目录、工作目录、Git 邮箱和公网 IP,并且是明文 HTTP 发到 134.209.82.225 的 8099 端口。

明文 HTTP 是个低级错误,我不打算把它说成高明行动。但它反过来提示了这类攻击的真实门槛:不需要高明也能成。真正致命的部分只有一个筹码,就是拿到上架权限。

还有一个信号说明这不是快进快出的活儿。它装的是 SSH 公钥,上线方式是反向隧道,大约每 60 秒重试一次,编辑器关掉之后仍然在跑,并且三平台都做了持久化,macOS 是启动项,Linux 写 cron,Windows 建一个名叫 SysMon 的计划任务、失败则退回启动目录。这套设计的意图是长期可交互的立足点,而不是装完就偷。而且脚本没有直接去读凭据的值,BleepingComputer 的判断是攻击者打算拿到访问权之后手动去取。

那个 bug 不能当防御

有一件事让很多人松了一口气:载荷在启用 SSH 服务这一步写错了,所以在大多数机器上隧道连不进来。

macOS 上的错误在 Phorion 的披露里写得很具体。脚本想用 systemsetup -getremotelogin 检查远程登录是否开着,但它是以普通用户身份跑的,这条命令返回的是管理员权限错误、退出码却是 0,输出里没有 Off。而脚本只在输出包含 Off 时才去启用 SSH,于是它跳过了启用这一步。Windows 上的错误更直接,它试图通过 /bin/sh 调 PowerShell 去装并启动 OpenSSH,而标准 Windows 上没有这个 shell,所以失败。

要注意的是这个 bug 不是防护。Hall 明确说了,在本来就开着远程登录的 Mac 上,或者用户事后自己打开的情况下,后门就是现成可用的。Cursor 也提醒,这个 bug 只在大多数 macOS 和 Windows 主机上成立,前提是没有用管理员权限启动 Cursor 这类相当罕见的情形。它装了 key、装了持久化、把主机详情发出去了,处置步骤一个都不能略。

还有一条最容易漏:卸载扩展不够。载荷会落下独立脚本继续跑,所以处置要按主机侧来做,而不是按插件侧来做。

为什么说这是新前线

把两件事叠在一起看,就明白这个判断不是在造词。

插件在 agent 时代的权限和周边资产都变了。扩展是拿 IDE 和当前用户的权限跑的,模块一加载就能碰本地文件、源码和开发工具链。而 agent 时代这些东西旁边躺着什么?BYOK 的模型 key、云凭据、各类 token,也就是载荷真正想要的那 40 个变量名的来源。市场侧的信任模型没有变,被保护资产的价值变了。

分发侧也一样。Sharma 说的那句「越来越多是 agent 和自动更新在装这些东西,而不是人在装」值得抄下来。自动更新把「人做一次判断」这一步整个删掉了,11 小时窗口、5,000 台机器,这个比例就是这么来的。

行业侧的量级也有人在做统计。据 Phoenix Security 的 campaign 追踪,VS Code 市场从接近零起步,在 18 个月里攒到 7 起已记录的 campaign;ReversingLabs 的检测数从 2024 年 27 起涨到 2025 年前十个月的 105 起;它追踪的 59 起 campaign 里,至少 14 起把 AI agent 工具当投递载体,手法包括 .cursorrules 与 CLAUDE.md 里的零宽字符隐藏指令、MCP server 注入、SessionStart 钩子。这些数字要打个折,Phoenix 是做供应链安全的厂商,这类统计本身就是它的市场材料,方向可信、绝对值存疑。但方向跟这次的形态是一致的。

三起对照:落点在上移

把今年的三起放在一张表里,能看出一个不太舒服的走势。

事件 被替换的位置 存活/影响 传统自查动作是否有效
LiteLLM 2026-03 CI 里未固定版本的 Trivy 被投毒,泄漏了发布凭据 PyPI 上约 40 分钟 部分有效
LiteLLM 2026-10 三名工程师的 GitHub CLI OAuth token 被盗,触发并批准了发布流程 PyPI 上约 2 小时 查源码、对 tag、审 sdist 全部给出「干净」
本次 第三方市场里的官方扩展上架条目 11 小时,最多 5,000 台 看发布者、看包名、看版本号全部失效

这条线的走向是在往上游挪:从依赖包,到构建产物,再到分发市场的上架位。每往上一格,就有一部分「自己事后能验证」的能力被拿掉。对依赖,你还能看源码;对 wheel,你还能对 Git tag;到了上架位,你没有可对照的东西,因为那本来就是官方的那一份。

关于前两起,站内写过更细的拆解,见《LiteLLM 又被投毒了》。

插件市场缺的,是包管理器十年前就有的东西

把两个生态的防线并排放,差距就出来了。

包管理器这十年攒下的东西大致是五样:lockfile 锁住确切版本、用 digest 而不是 tag、发布产物的签名与 attestation、企业私有源做路径隔离、以及 SBOM 这类可审计清单。这五样不是理论,站内拆过的另一起事件刚给出实证。LiteLLM 十月那次,浮动的标签体系(latest、main-latest、main-stable)全线中招,而走隔离私有发布路径的企业私有 registry 没有受影响。同一批攻击、同一批包,有没有可验证性和隔离路径,结果就是不一样。

插件市场这边,这几样基本都缺或者很弱。扩展通常没有 lockfile 级别的版本固定,宿主默认开着自动更新,发布产物一般没有可验证的 attestation,权限却按 IDE 加当前用户来给。反过来看,Docker 那边的 MCP catalog 倒是把构建 attestation 和签名 SBOM 做成了默认,还可以在运行时验签。也就是说同类问题在别的生态里已经有解,只是插件市场还没补上。

我想给的判断很直白:插件市场的安全水位比包管理器落后大约十年,而它承载的资产比包管理器更值钱。 这个落差就是这次事件能发生 11 小时的结构原因,不是某个工程师的疏忽。

能立刻做的是把插件当依赖来管:固定版本、关掉自动更新、把「谁装了哪些扩展、从哪个市场来的」变成一份清单。这三件事今天下午就能做完,而且不依赖任何厂商改产品。

这次处置里,最关键的一步不是下架

Cursor 的动作有三个:下架恶意版本并关停整个市场做审计、轮换自己的密钥、联合托管商把攻击者的服务器打掉。

我认为最有效的一步是轮换密钥,而不是下架。理由跟根因未明有关:下架只处理了已经知道的那一个包,而密钥轮换处理的是「同一条路径还能不能再用」这个你还没弄清的未知。在不知道对方怎么拿到上架权限的情况下,轮换是唯一能同时覆盖已知和未知的动作。

关停整个市场的代价很大,所有人的插件更新都得停,但它是唯一能证明「只有这一个包被改」的办法。这个取舍值得记下来:当发布位的完整性本身被质疑时,你能给出的最强证据是把发布路径重新走一遍,并把结果公开说出来。

打掉攻击者服务器这个动作的效果是双份的,既断了回传也断了隧道。但它同时销毁了取证现场。这里有个真实的两难,我给不出更好的答案,只能指出来:响应速度和取证完整性在这一步是冲突的,这次他们选了速度。

三个判断

发布者身份不再是信任锚。 这一条对个人开发者的含义是具体的:市场页面上你能看到的那些信号,名称、图标、下载量、发布者认证,这次的攻击一个都没碰坏,全是真的。可用的替代是盯行为而不是盯身份,一个补全代码的插件为什么要往 authorized_keys 里写东西、为什么要起一条 SSH 连接、为什么要在重启后还跑着。Sharma 给的判断标准很干脆,一个编码扩展在装 SSH 密钥,这件事本该在几秒内被抓住。这句话在技术上成立,在工程上代价很高,因为「几秒内」意味着你得有主机行为的连续观测,而绝大多数开发者机器上没有。

责任会在厂商之间流转,处置成本落在用户这边。 这次两家的声明都很克制,一家说不是我们造的,一家说不是我们的系统被攻破,而「怎么进的市场」没有解释。我不觉得这是谁在藏,我更倾向于它是这类事件的结构:只要分发市场是第三方,每一次都会以各方都能自证清白、用户去轮换凭据结账。能做的是把自己这侧的处置提前写进流程,比如哪几台机器开着 SSH、哪些环境变量里躺着生产凭据、出了事用哪台可信机器去轮换,而不是等公告出来再想。

agent 时代把这一层的杠杆放大了,而这跟站内写过的那条线是同一个结构。 插件就是 agent 的能力来源,所以「装一个插件」的语义已经变了,它从给自己加个功能,变成了给一个会自动执行东西的程序加权限。今年早些时候写 MCP 供应链那条线(《MCP 供应链安全》)时的结论是 npm 的教训在 agent 生态重演,这次的差别在载体换成了 IDE 市场,而被替换的是真品。载体还会换,结构不会。

如果你在那 11 小时里更新过

版本号先对一下:2.1.312 和 2.1.313,Windows 与 macOS。Phorion 建议组织层面直接排查环境里有没有用过这两个版本,发现用了就启动应急响应。

检查顺序按主机侧来。先看 ~/.ssh/authorized_keys 里有没有一条标记为 svc-telemetry 的条目。别只卸载扩展,载荷落了独立脚本,所以还要看 macOS 的启动项、Linux 的 crontab、Windows 里名为 SysMon 的计划任务和启动目录。然后轮换这台机器能碰到的所有凭据和会话,并且要在一台可信的机器上做这件事,因为被污染的机器上任何操作都可能被看着。想确认有没有人真的登进来过,可以按 Phorion 的建议查 SSH 日志里来自 localhost、用的正是 svc-telemetry 这个 key 的登录。

Cursor 已经发过检查命令和 macOS/Windows 的清理脚本,两家也都给了失陷指标。

一句话收在这里:这次事件里值得反复看的是「没有冒充可识别」这七个字。它把供应链防御里最便宜的那一层,也就是看名字认人,整层拿掉了。剩下的那层要花钱,要建观测,而且得由每个用 agent 的团队自己出。

相关阅读:《LiteLLM 又被投毒了》、《MCP 供应链安全:npm 的惨痛教训正在 Agent 生态重演》、《OpenCode 被「蒸馏攻击」打穿》

By AI博士 万戈