夜雨聆风学习资料网

ARTICLE · 1282880

投毒 AI 插件:你的编辑器里,多了一把别人的 SSH 钥匙

投毒 AI 插件:你的编辑器里,多了一把别人的 SSH 钥匙

QUOTE

十一个小时里,Cursor 的扩展市场上多了一个叫 Anthropic.claude-code 的插件。它没有跟你说过一句话,却在授权文件里写下了一把公钥,标签写着“服务遥测”。官方后来只给了一句提醒:卸载,可能不够用。

—— 赛博大哥大

01

THE INCIDENT

十一个小时,和一个看起来完全正常的版本号

2026 年 10 月 29 日,Cursor 官方博客发了一篇标注为 company、作者 Cursor Team、阅读时长五分钟的安全通告,标题是“Security notice — malicious version of Anthropic.claude-code (2.1.313) identified in the Cursor Extension Marketplace”。页面最下方留给读者的联系方式只有一个邮箱:security@cursor.com。

通告开篇只有三句话,却已经把这起事件的骨架定完了:涉事包是 Anthropic.claude-code 2.1.313;这句必须原样抄——“This malicious version of the extension was not developed by Anthropic.”;以及“At most 5,000 users were affected, and we will reach out directly.”

先说那个 5000。它的性质是“at most”,是官方给出的上限估计,不是确认安装数。路透社在报道里明确标注这是“not a confirmed count”。官方承诺会直接联系受影响用户,但通告本身从头到尾没有公布真实的下载量。

顺带纠正一个流传出去的数字:网上出现过“4100 名程序员受影响”的说法。核对下来,所有可查来源——官方通告本身、路透社的转述、几家安全媒体的复述——一致只有“最多 5000”这个上限,没有任何一个来源给出 4100。所以这篇稿子里只写 5000,并且明确它是上限。

时间窗口是整起事件里最精确的一块拼图。官方写的是“between about 2:27am PT and 1:35pm PT”。换成北京时间,是 10 月 29 日 17:27 到 10 月 30 日 04:35,十一个小时零八分钟。巴黎时间的写法是 10:27 到 21:35,换算完全对得上。

这篇通告的结构本身也值得留意:目录只有七节——What happened、What we did、What you should do、Check whether you are impacted、Remediate affected machines,加上两节入侵指标。前面四节讲发生了什么、做了什么、该做什么,最后一节给出的是可以复制粘贴去自查的命令和哈希。

官方通告的 What happened 一节。四条恶意行为按执行顺序排列,最后一句写着:攻击者服务器已不再可用。整节文字里最重要的其实是括号里的那句让步——除极少数以管理员权限启动 Cursor 的情况外,这一步会失败。

下面这张图是官方通告的原貌。四条恶意行为按执行顺序写下来,读完你会发现:它描述的不是一次入侵,而是一次装机。

02

THE PACKAGE

投毒的到底是什么:一个被换掉内容的外壳

恶意版本的载体是两个 VSIX 安装包。官方给出了完整哈希:darwin-arm64 版本的 SHA-256 是 432ccdee3801f99e52b8fe31f69ea9870118e96ea7ef9ecabed1479621b5ab62,MD5 是 da5469c4221775e9fe2e413e59ca7fd9;win32-x64 版本的 SHA-256 是 3de1722901165769893bef57c72594e9a54459faa23f3091b136b79966edd081,MD5 是 bd3b71ddf3d0cc3af76249afd2c0eda1。要确认自己机器上装的是不是坏包,对着这两个值算一遍就行。

官方给的判定方法更直接:在 anthropic.claude-code-2.1.313-darwin-arm64 或 anthropic.claude-code-2.1.313-win32-x64 的扩展目录里,extension.js 这一个文件内会同时出现 134[.]209[.]82[.]225 和 svc-telemetry 两个字符串。正常版本不会有。

版本号本身也是伪装的一部分:2.1.313 和正常的补丁版本号看不出任何差别,攻击者不需要发明一个新版本号,只要把 2.1.313 这个包的内容换掉。所以任何只按版本号做的黑白名单,在这里都会失效——这也正是官方为什么把两个完整哈希值直接列出来的原因。

但“它长得很像 Anthropic 的插件”这件事本身,恰恰是这次攻击最省力的一环。Cursor 的扩展市场是一个聚合层,它自己的扩展指南里就提醒过:同一个扩展标识符,在 Open VSX 和微软市场里,发布者和代码可能并不是同一份。

标识符是公开的、固定的、可预测的。这正是依赖混淆这类供应链攻击最喜欢的前提——不需要骗过任何人,只需要抢在一个名字前面。

Cursor 官方在 X 上给出了范围:这不影响从官网、Grok Bot、Grok 或其他 SpaceXSI 产品下载的扩展;Anthropic 那边已经把干净的 2.1.314 发布到了 Open VSX 和微软市场;所有客户都被要求升级到 2.1.314。

也就是说,受害面被官方圈在了一个很窄的圈子里:只有在 10 月 29 日那十一个小时里、从 Cursor 自己的市场、拿到 2.1.313 的人。

03

THE LOADER

六十六行代码,不需要你说一句话

官方通告写的是“恶意版本”,但它没有说清楚这个“版本”是怎么来的。The Hacker News 引述安全研究人员的逆向结果给出了一个具体答案:被篡改的 extension.js 前面,被插进去了一段六十六行的 loader。

位置是关键。这六十六行排在正常逻辑之前执行,扩展一加载就跑,跟你有没有打开对话框没有关系。这句话值得单独拎出来:用户不需要跟 AI 说过任何一句话,恶意代码已经跑完。

loader 做的第一件事,是先 import system、file、network、crypto 这几个模块,然后才把控制权交还给正常的扩展代码。它把自己的位置摆在扩展的入口,而不是某个功能分支里。

还有一个更阴的细节:大量错误被 suppress 掉了。恶意步骤失败的时候,扩展照常工作、照常对话、照常不报错。安全研究员 Paul McCarty 的分析说得很准——用户没有任何察觉的窗口。连失败都不给用户看。

把这两件事拼起来,loader 的设计意图就清楚了:它要的不是运行一次某个功能,而是抢在扩展的任何逻辑之前,先把系统、网络、文件、加密这几样能力拿到手,再把自己藏进一段看起来像正常初始化的代码里。对一个每天要读仓库、写文件、调接口的 AI 编程插件来说,这几样能力本来就是它被授予的——攻击者等于直接继承了这套权限。

环境变量只取名字,不取值。研究者统计的是:最多取四十个变量名,按 KEY、TOKEN、SECRET 这类关键词去挑。

研究人员还补了一条官方没写的:Linux 上除了在 ~/.config 下写文件,还额外加了 crontab 条目。官方通告里只列了 macOS 和 Windows 两条持久化路径。

至于没查到的部分,也要说清楚:静态审计没有发现二级载荷下载,脚本和隧道密钥都内嵌在扩展包里。但静态审查看不到隧道建立之后发生的事——那正是攻击者真正会用的那一段。

所以这次事件的性质要重新定位:出错的不是模型,不是提示词,不是 AI 说错了什么话。出事的是分发渠道本身。

04

THE CHAIN

四步:采集、留钥匙、架隧道、上报

官方把恶意行为列成了四条,顺序就是实际执行顺序。

第一步,采集主机信息:hostname、username、操作系统、CPU 架构、home 目录路径、环境变量名、工作目录、Git 配置里填的邮箱、公网 IP。

公网 IP 走的是 ifconfig.me 和 api.ipify.org 这两个公开服务。官方特意加了一条注:这两个是合法服务,单独访问它们不构成入侵指标。这句注写得很专业——它一边承认了攻击链的这一环,一边不给人误判。

第二步,往 authorized_keys 里追加攻击者的 Ed25519 公钥,打开本地 SSH 服务,再架一条反向隧道。公钥标签写着 svc-telemetry,也就是服务遥测。

打开本地 SSH 服务这一步,macOS 用的是 systemsetup -setremotelogin on,Windows 用的是 Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0。隧道命令是 ssh -N -R “*:0:localhost:22”,配合 autossh -M 0 做保活。

隧道参数值得抄下来:StrictHostKeyChecking=no、UserKnownHostsFile=/dev/null、ServerAliveInterval=30、ServerAliveCountMax=3、ExitOnForwardFailure=yes、IdentitiesOnly=yes。翻成中文就是——不问你是否信任这台机器、不记录主机密钥、每三十秒保活一次、失败就不许连。

第三步,做持久化。macOS 写 ~/Library/LaunchAgents/com.apple.sysmond.plist,标签是 com.apple.sysmond;Windows 建一个名为 SysMon 的计划任务,试图以 SYSTEM 身份运行,再用启动文件夹里的 sysmon.cmd 作为兜底。后台脚本大约每六十秒重试一次隧道连接。

第四步,上报。用 HTTP POST 把主机信息和后门状态发到 134[.]209[.]82[.]225 的 8099 端口的 /beacon 路径,同时还会尝试回环地址 127[.]0.0[.]1:8099/beacon。

还有两处细节值得记下来。那把公钥的完整形态是以 ssh-ed25519 开头的一长串 Base64,结尾注释是 svc-telemetry,指纹是 SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk。临时文件的命名规则是 .stk_ 加上十位十六进制,放在系统临时目录下——它看起来像是为每次运行生成一个独立状态文件,也像是在给攻击者自己留一个可识别的路标。

官方公布的入侵指标之一段:包哈希、网络端点、SSH 公钥指纹。公钥指纹 SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk,隧道密钥指纹 SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ。

图里这些哈希和指纹,是官方留给受害者的一句可执行的话:不用猜,对着算一遍就知道。

05

THE HALF FAILURE

失败了一半的后门,更难缠

官方在第一条里写了一句让步的话,这是整篇通告最重要的战术细节:“Outside of highly unusual circumstances where Cursor was started with administrator privileges, due to errors in the malicious code, this step would fail.”

紧接着官方又补了一句更精确的:开启本地 SSH 服务需要管理员权限,而恶意扩展在大多数 macOS 和 Windows 主机上拿不到这个权限。在这些机器上,这一步会失败,攻击者无法通过隧道登录进来。但扩展仍然添加了攻击者的 SSH 公钥、仍然安装了持久化、仍然把主机信息发给了攻击者。最后一句是:无论如此,请按下面的处置步骤执行。

翻译成人话:大多数机器上,隧道根本没建起来。但公钥写进去了,持久化落盘了,主机信息发出去了。

这里必须算清楚攻击者的账。这场行动里,后门成功率为零,情报收集成功率为满。一个理性的攻击者,为什么接受这个交换比?

因为他要的本来就不是今天的账号,是钥匙。写进 authorized_keys 的那行公钥是一张长期门票——任何时候这台机器的 SSH 服务开着,那张票就能用上。而不少开发者的 authorized_keys 里本来就挂着好几把公钥,包括公司下发的那把。多一行,不容易有人注意到。

所以这不是一次入侵失败,这是一次预埋成功。失败的是隧道这个执行器,成功的是钥匙这张长期凭据。

换个角度说,这一步的门槛低得惊人:往 authorized_keys 里写一行,不需要管理员权限,不需要任何凭据,不需要用户在界面上点任何确认。对攻击者来说几乎免费。而一旦本地 SSH 服务哪天被打开——开发机上常开、容器里常开、老服务器上遗留的也常开——那张票立刻就有用。

对受害者来说,这个区别毫无安慰作用。这就是为什么官方的处置建议不是“如果你发现隧道通了才需要处理”,而是“无论是否被入侵,都按下面步骤做”。

06

THE PERSISTENCE

卸载不是终点,甚至不是起点

官方在“你应该做什么”那一节写了两句最狠的话。

第一句:Uninstalling the extension may not be sufficient — the payload drops standalone persistence scripts that keep running。卸载扩展可能不够用,因为载荷会往磁盘上扔独立于扩展本身的持久化脚本,它们会继续跑。

第二句:The limited env-var collection does not rule out later credential access over the backdoor。环境变量只收集了名字这件事,并不能排除攻击者日后通过后门获取凭据。

第一句对应的是一个非常普遍的直觉:出事了先卸载扩展。官方说不行。

第二句对应的是一个更要命的推理。攻击者只收集了环境变量的名字,没有值。但那四十个名字本身就是一张攻击地图——名字会告诉攻击者这台机器上有什么值得偷:某个云厂商的访问密钥、某个数据库的连接串、某个部署服务的令牌。

官方公布的落地文件与命令清单。macOS 的 ~/.config/.smt、~/.config/.smtk、临时目录下的 .stk_ 加十位十六进制、LaunchAgents 里的 com.apple.sysmond.plist;Windows 的 .config 目录、计划任务 SysMon、启动文件夹里的 sysmon.cmd。最后一栏是命令行的具体形态。

官方给的两个处置脚本是 remediate-macos.sh 和 remediate-windows.ps1。权限要求写得很具体:前者必须以受影响用户身份运行,不要用 root;后者必须在以管理员身份打开的 PowerShell 里执行。两者做的事一样——移除恶意扩展、清掉持久化机制、杀掉仍在跑的隧道进程、移除攻击者公钥,而且只要还有任何残留,就以非零状态退出。

最后一条,也是最容易被漏掉的:从一台可信的设备去轮换凭据和会话。不是在这台可能被动过手脚的机器上改密码,是在另一台机器上改。

07

THE RESPONSE

关停整个市场

Cursor 自己的处置分四步,官方列得很干净:检测到即从市场移除恶意版本并阻断进一步分发;出于过度谨慎,全站关停 VS Code 扩展市场;审计访问记录,确认没有其他扩展被动过;轮换密钥、重建市场、重新上线。同时让托管方把攻击者的服务器下线。

官方通告的 What we did 一节。四条处置动作,从立即下架到重建市场重新上线,最后一条是让托管方把攻击者服务器下线。

全站关停这个动作,值得单独评价一次。往轻了说,这是负责任;往重了说,这是失控。整个 Cursor 扩展市场在同一天下午不可用,所有在那个市场上分发扩展的开发者一起停摆——他们跟这起攻击没有任何关系,损失却是实打实的。

关停期间,那些靠 Cursor 市场分发扩展的小团队,损失的是真实的用户和收入。他们既没有参与投毒,也没有能力阻止投毒,却要为这次事故的信任修复一起买单——市场越大,越是这样。

但换个角度看,这一关也是唯一诚实的选择。Cursor 自己刚刚证明了一件事:这个市场可以在十一个小时里被放进一个带后门的包,而且没有一个人发现。既然一次投放没被发现,那在查清楚之前,最短时间尺度的安全姿态就是把门关上。

而这也解释了官方为什么把处置顺序写成先下架、再全站关停、再审计、最后重建——它不是过度反应,它是在承认自己那套审核机制这次没生效。

反讽的是,页面最下方那行小字写着 SOC 2、ISO 27001、ISO 42001、AIUC-1 Certified。这四行认证标识贴在同一个页面的最底部,描述的恰好是这次没做到的事。

10 月 30 日,Cursor 官方在 X 上补了时间线:当天关停市场,与相关服务商合作清除恶意程序,确认没有进一步风险后重新开放市场。

08

THE GAP

官方没有回答的那个问题

Numerama 提出了这次事件里最该被追问、却没有人回答的问题:“The advisory does not say how the attacker managed to publish an extension bearing the name of Anthropic in the Cursor marketplace.” 通告没有说明,攻击者究竟是怎么把一个打着 Anthropic 名字的扩展发布进 Cursor 市场的。

官方说了“我们审计了访问,确认没有其他扩展被动过”,也说了“我们轮换了密钥、重建了市场”。但它始终没有说:当初那个市场,对一个由第三方上传的、冒用 Anthropic 名字的扩展,到底是怎么审核的。

这个缺口不在事后,在事前。审核环节要么不存在,要么存在但被绕过。无论哪一种,都意味着发布者身份和包内容之间,至少有一条链路是没有被验证的。

一个真正经过验证的市场,至少要在三件事上给出证据:发布者身份与扩展标识符的绑定关系、包体的签名与哈希、以及上架前的自动化行为检测。这次事件里,至少第一项和第二项没有拦住任何东西。

更麻烦的是,重建后的市场还是同一个第三方来源生态。修的是钥匙,换的是锁芯,供应链的结构没变。

至于攻击者是谁,官方没有定性。第三方分析推测是独立的网络犯罪者,且不与任何已知组织挂钩;关于是否与中国背景有关,官方从未表态,这里也不替它下结论。

但有一件事无论是谁做的都成立:这个攻击者选了一个价值密度最高、权限最高、也最习惯点一下就装的靶子。

09

THE PRECEDENT

不是第一次,只是靶子换了

往前的历史里,往开发者的编辑器里塞后门这件事早就不新鲜。Open VSX 上出现过被安全厂商溯源的恶意扩展,伪装成语言支持包,把开发机的加密钱包当成目标;2021 年之后,依赖混淆成为公开讨论的供应链攻击模式——在公开仓库里放一个名字和官方包极为接近的包,等着 CI 流水线自动把它拉下来。

但这次有两个地方不一样。

第一,标的变了。以前被投毒的是编译工具链、语言服务器、构建脚本。这次被投毒的是一个 AI 编程代理——一个能读你整个仓库、能改代码、能执行命令的插件。权限等级完全不是一回事。

更具体的对比是这样的:语言服务器出错,最坏情况是多报几条编译错误;构建脚本出错,可能污染一次产物。而一个能执行命令的 AI 编程插件出错,作用域是整台机器,加上它能访问到的所有远端——因为它本来就被授权这么干。

第二,受众变了。以前瞄准的是开发者终端;现在瞄准的是把 AI 编程工具装进生产工作流的那批人。他们的 authorized_keys 通常管着跳板机、测试服务器、云主机。

还有一个更冷的事实:这批人正在成规模地把凭证交给模型。工具读 .env、读 CI 配置、读密钥文件,本来就是这类产品的日常功能。所以 AI 编程工具和凭证之间的距离,比任何传统插件都近。

这次事件真正的特殊之处在这里:以前我们说“装插件要小心”,说的是插件会读你的代码。这次是插件会拿到一把能直接登录你服务器的钥匙。

10

THE SCALE

上限五千,意味着什么

现在回到那个 5000。

想一想“最多五千名用户受影响”意味着什么:这五千人不是普通用户。每一个都在自己的开发机上装着 AI 编程工具,并且愿意让它连上代码仓库。

他们身上同时具备三样东西:本机的 SSH 私钥、跳板机和服务器的授权、一台公网可达的机器。

再看那份环境变量名单。最多四十个名字,按 KEY、TOKEN、SECRET 匹配。把它和开发者的典型环境放在一起看,名单几乎可以默写出来:云厂商访问密钥、数据库连接串、CI 的部署令牌、各类服务的私钥。

beacon 上报的内容是主机信息和后门状态。这些信息单独看价值有限,但拼在一起就是一份完整的资产清单:有哪些机器、分别是谁在用、代码库在哪个目录、Git 邮箱属于谁。

官方特别强调“只取名字不取值”,这句话是对的,但对攻击者并不构成安慰。因为下一步根本不需要从这批机器上偷东西。他有钥匙,有机器清单——beacon 传回来的主机信息、Git 邮箱、工作目录——还有时间。

而且反连通道本来就是按长期驻留设计的。三十秒保活、六十秒重试,意味着一旦权限窗口打开——用户重启一次、以管理员身份启动一次 IDE、装一次需要提权的软件——连接就会自动建立。

所以官方那句“无论如何都按下面的步骤处理”,真的是字面意思。

最后补一个观察。这次被投毒的包名,是 AI 编程工具里最热门的那一个。攻击者挑中它,本身就是一种判断——目标用户群的价值密度最高、权限最高、也最习惯点一下就装。

11

THE ACTION

今晚就能做完的五件事

官方给了五条处置建议。这里按今晚就能做完的顺序重排一遍。

第一步,自查。下面这两段是官方原文,macOS 一行命令,Windows 一段 PowerShell。

# macOS

grep -qs svc-telemetry ~/.ssh/authorized_keys && echo "svc-telemetry key found" || echo "No key found; machine not impacted"

# Windows PowerShell

$files = "$HOME\.ssh\authorized_keys", "C:\ProgramData\ssh\administrators_authorized_keys" | Where-Object { Test-Path $_ }

if ($files -and (Select-String svc-telemetry $files)) { "svc-telemetry key found" } else { "No key found; machine not impacted" }

官方通告的 Check whether you are impacted 一节。macOS 用一行 grep,Windows 用一段 PowerShell,检查同一个关键词:svc-telemetry。查出来就说明机器受影响,需要继续走处置流程。

第二步,查遥测。官方建议在终端、网络和扩展安装三类遥测里搜索上面那批指标:134[.]209[.]82[.]225、svc-telemetry、134[.]209[.]82[.]225:8099/beacon、com.apple.sysmond、SysMon、sysmon.cmd、.smt、.smtk、.stk_。

如果是 macOS,顺手看一眼 ~/Library/LaunchAgents 目录里有没有 com.apple.sysmond 开头的 plist,以及 ~/.config 下有没有 .smt 和 .smtk 两个文件;Windows 上看任务计划程序里有没有名为 SysMon 的任务、启动文件夹里有没有 sysmon.cmd;Linux 用户再检查一次 crontab,那一条是研究人员补进通告的。

第三步,隔离。对出现载荷执行或后门安装证据的主机,先断网隔离,再判断要不要重建。官方用的措辞是评估这台主机是否应当重建,它没有替你做这个决定。

第四步,跑脚本清理。macOS 用 remediate-macos.sh,以受影响用户身份运行,不要用 root;Windows 用 remediate-windows.ps1,必须在管理员 PowerShell 里跑。两个脚本只要发现残留,就会以非零状态退出。

第五步,从可信设备轮换凭据和会话。

还有两件不在官方清单里、但必须做的事。第一,升级到 2.1.314,并且确认自己装的是干净版本而不是从 Cursor 市场拿的那份旧包。第二,排查 authorized_keys 时如果发现不止多了一行,而是多了几行不相干的公钥,那你要处理的问题就比这次事件大得多了。

∞

THE QUESTION

谁该为一次点安装负责

这次事件真正改变的,不是有多少人被影响,而是 AI 工具的风险位置变了。

在此之前,AI 编程工具的风险被默认理解成模型会不会说错话、会不会写出坏代码。这次证明的是另一件事:出错的地方不在模型里,在分发渠道里。一个模型再聪明,也管不了自己被谁换过包装。

更有意思的是,一个纯文本工具不会出事,一个能执行命令、能读文件、能访问网络的插件会出事。而 AI 编程工具恰好同时具备这两种属性,它的分发方式还是从市场里点一下安装。信任模型建立在一个几乎没有摩擦的动作上——这正是依赖混淆攻击最有效的土壤。

官方那句 Uninstalling the extension may not be sufficient,其实是一句关于分发渠道的判词:出了事,卸载这个动作不再是终点,甚至不是起点。你得先知道它在你机器上留了什么,才知道该清理什么。

于是问题回到最本质的那一层:谁该为 AI 工具市场的审核负责?是 IDE 厂商,是第三方市场,是包名的原厂,还是那个按下安装的人?

目前的答案似乎是最后一位。因为在整个链条里,只有他还在用肌肉记忆做决定。

十一个小时、五千这个上限、那把还躺在 authorized_keys 里的公钥,是这次事件留下的三个具体坐标。它们指向同一件事:在 AI 工具被装进生产环境之前,我们还没有一套可信的分发验证机制。

赛博大哥大

AI 与前沿科技深度长文

我是赛博大哥大,主打 AI 与前沿科技的深度长文。不追热点、不凑日更,只把值得反复看的议题一篇讲透。

如果这篇有收获,欢迎点赞、在看、转发三连,我们下篇见。

— END —

洞见智能浪潮 · 探寻未来之道

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料