8月20日,Rust官方在同一天干了两件事:发布1.98.0新版本,然后发了一篇和版本发布完全不沾边的安全公告——crates.io上被投毒了。Rust官方博客
被投毒的不是什么无名小包,而是累计下载超过2.5亿次的基础库arrayref。crates.io如果你是那种"项目能编译就万事大吉"的Rust开发者,这次事件值得你花三分钟认真看一下:因为它恰恰证明了,编译成功从来不等于安全。知乎

86分钟里发生了什么
先把时间线捋清楚(均为UTC时间):
07:15,Rust安全响应团队收到报告:一个叫proc-macro1的crate是恶意的——名字只差一个数字,碰瓷的是大名鼎鼎的proc-macro2。它的库代码看起来像正经包的拷贝,真正的恶意逻辑藏在build.rs里:构建脚本会下载后续的攻击载荷。
同一时间窗口,安全团队发现三个正常维护的crate被"劫持发布"了恶意新版本:arrayref@0.3.10、internment@0.8.7、append-only-vec@0.1.9。项目源码基本没动,构建也能正常通过,多出来的只有一个指向proc-macro1的依赖声明。
更狠的一手是:攻击者在同一分钟把arrayref之前的一批正常版本yank掉了。这样依赖解析时,恶意版本更容易被Cargo选中,你看到版本号也不会觉得异常。
08:41到09:25之间,三个恶意版本陆续被官方删除。它们分别只存在了86分钟、90分钟和107分钟。RustSec
另外有六个恶意crate(proc-macro1、proc-macro-en、aovine、arone、aronenao、tinymember)被整体删除,官方明确:这些包的所有版本都应视为恶意。arrayref的维护者被认为是无辜的——大概率是电脑或凭据被盗,官方已锁定账号并尝试联系本人。Rust官方博客
为什么Rust的"安全"没拦住这次攻击
这是社区这两天吵得最凶的问题。B站相关视频下点赞最高的评论只有五个字:security != safety。哔哩哔哩
说得精确点:Rust引以为傲的是safety——内存安全,编译期挡住悬垂指针、数据竞争这类问题。但这次攻击走的是security的口子:build.rs是Rust生态里完全正常的机制,很多正经项目都靠它生成代码、检查环境。攻击者不需要改arrayref的任何核心函数,只要你的构建流程执行到依赖解析,构建脚本就先一步在本机或CI上跑起来了。Rust官方博客
按安全公司Aikido对第二阶段载荷的分析,它会翻找Chromium系浏览器(Chrome、Brave、Edge)的用户配置数据,检查浏览器扩展存储里的加密货币钱包数据,还带持久化和接收远程命令的能力。翻译成人话:开发者的登录态、钱包扩展里的敏感数据、源码和构建环境,都在它的射程之内。Aikido
但要强调一句:这是攻击链的"能力",不等于"已发生的损失"。官方没有公布实际有多少机器执行过载荷,而且按Wiz的分析,载荷的浏览器相关行为目前停留在枚举已保存的登录项,并没有直接获取加密凭据材料本身。Wiz顺便辟个谣:这两天有区块链安全周报把这事和"比特币冷钱包被盗1.1亿美元"放在同一期里,二者没有证据上的直接关联,别混着传。
这次真正的功臣,是你平时懒得看的Cargo.lock
RustSec公告(RUSTSEC-2026-0260)里有个数据值得划重点:恶意版arrayref@0.3.10总共被下载2285次,不到当时arrayref全版本下载流量的10%。RustSec原因很简单——大多数用户的Cargo.lock里锁着老版本,依赖解析根本轮不到这个新版本。
这是个挺反直觉的结论:一个2.5亿下载量的包被投毒,86分钟里真正中招的下载只有两千多次。不是攻击者手法不行,而是lockfile这道"平时没人夸"的防线,把绝大多数人挡在了外面。反过来说,如果你或者你的CI习惯不提交Cargo.lock、每次都做全新解析(比如某些Docker构建流程),这次就是暴露面最大的那批人。
这个暴露面有多宽,可以看Wiz基于自家遥测的统计:被波及的Rust包里,arrayref出现在全部被扫描环境的35.7%、含Rust环境的77.7%,而append-only-vec和internment分别是3.7%和3.0%(均为Rust环境口径)。换句话说,它早就以间接依赖的身份渗透到大多数Rust项目里了——这也是为什么第一层自查必须翻lockfile,而不是只看显式依赖。

现在该做什么:四层自查
截至9月1日,crates.io上arrayref的最新版本仍是0.3.9,官方还没有发布新的可信版本,RustSec的建议是把受影响版本视为"无修复版"。crates.ioRustSec自查可以按这四层来:
查锁文件。翻项目里的Cargo.lock,确认没有arrayref 0.3.10、internment 0.8.7、append-only-vec 0.1.9,以及proc-macro1等六个恶意包。注意别只看顶层依赖,arrayref大概率是以间接依赖的身份躺在你项目里的。知乎
查本地缓存。官方给的命令是去~/.cargo/registry/cache里搜这几个包的归档文件(arrayref-0.3.10.crate、internment-0.8.7.crate、append-only-vec-0.1.9.crate,以及proc-macro1/proc-macro-en/aovine/arone/aronenao/tinymember的任意版本)。Rust官方博客
查构建环境。凡是恶意版本存活期间跑过构建的开发机和CI,不能只是"重新编译一遍"就完事——被删掉的包不会让已执行的脚本回到没执行的状态。按你们组织的凭据应急流程,评估浏览器登录态、钱包扩展、环境变量和CI密钥要不要轮换,留好构建日志和网络日志。Wiz
锁版本。短期内把arrayref固定在0.3.9或更早,比让解析器自由漂移可控。固定不是永久方案,但在上游发布链路没厘清之前,它是更稳的选择。
接下来值得盯的三个信号
值得盯的信号有三个。一是crates.io会不会借这次事件推出实质性的安全加固:目前官方公告只建议开发者自查本地依赖,还没出现账号保护、发布审核或构建脚本沙箱这类机制层面的动作。Rust官方博客二是arrayref维护者回归后会不会发新版本,RustSec公告目前"no patched versions"的状态什么时候更新。三是官方会不会披露维护者账号到底是怎么被盗的——这决定了其他人该重点防钓鱼、防恶意软件还是防凭据复用。
最后说一句:这次事件不是Rust的打脸时刻,反而是lockfile和快速响应机制的一次实战检验——86分钟下线、官方当天发公告、RustSec当天挂出advisory。但它确实给所有Rust项目提了个醒:你审查业务代码再仔细,依赖树、构建脚本和CI缓存这几层,也该定期看一眼了。