今天上午,有个哥们在群里发了一句话:
"axios 被投毒了。"
我第一反应是不可能。axios 每周 1 亿次下载,npm 上 Top 10 的包,谁敢动它?
然后我去翻了 GitHub issue,翻了安全公司的分析报告。越看越不对劲。
axios 的 GitHub 仓库里,一行恶意代码都没有。你盯着源码看一万遍,什么都发现不了。
问题根本不在源码里。
到底发生了什么
有人偷了 axios 维护者的 npm 账号,绕过 GitHub,直接往 npm registry 发了两个"官方版本"。
axios 代码本身没改。只是在 package.json 的依赖里加了一个你从没见过的包:plain-crypto-js。
你 npm install 的瞬间,这个包的 postinstall 脚本自动跑起来:检测操作系统,下载远控木马,连上攻击者服务器。然后自我删除,把 package.json 替换成干净版本。
你事后翻 node_modules,什么痕迹都没有。
就好像你去五金店买了一把锁,品牌对、包装对、外观对,但里面被人换成了带后门的。你装上了,用着正常,别人随时能开你家门。普通漏洞是锁有缺陷,换一把就行。这次是锁在到你手里之前就被掉包了。
攻击时间线
我把时间线拉出来:
T-18小时 :攻击者用一次性账号发布了 plain-crypto-js@4.2.0。
注意,这个版本是干净的。内容就是合法 crypto-js 的复制品,零恶意代码。
为什么要发一个干净版本?在 npm 上建立发布历史。一个零历史的新包突然被大包依赖,会触发安全警报。先"养号",18 小时后再动手。
T-30分钟 :发布 plain-crypto-js@4.2.1,注入恶意 postinstall 脚本。
T=0 :用被盗的维护者账号,发布 axios@1.14.1。
T+39分钟 :发布 axios@0.30.4。1.x 和 0.x 两条版本线,一次全覆盖。
T+3小时:npm 下架恶意版本,窗口关闭。
18 小时预埋,39 分钟把两条版本线全覆盖,3 小时后窗口关闭,痕迹自毁。
安全公司 StepSecurity 的评价是"针对 npm Top 10 包有记录以来最精密的供应链攻击之一"。
还有个细节:恶意载荷在 npm install 开始后 2 秒内就开始向攻击者服务器回传信息。比 npm 解析完其他依赖还快。你来不及按 Ctrl+C。
GitHub 上为什么看不出来
npm registry 和 GitHub 是两个独立系统。你在 GitHub 上看到的代码,和你 npm install 装到的东西,可以完全不是同一个东西。
有维护者的 npm token,就能绕过 GitHub 的代码审查、CI/CD、所有你能看到的流程,直接往 registry 发包。
axios 所有合法的 1.x 版本都通过 GitHub Actions 的 OIDC Trusted Publisher 机制发布,有密码学签名,和 GitHub 工作流绑定。1.14.1 没有。纯手动发布,没有 OIDC 绑定,没有 gitHead。
这个差异写在 npm registry 的元数据里。但你平时装包的时候查过 registry 元数据吗?
我也没查过。
现在该做什么
用了 axios 的项目,花 5 分钟跑一遍。
第一步:查 lockfile
打开你的 package-lock.json、pnpm-lock.yaml 或 yarn.lock,搜这三个关键词:
axios@1.14.1axios@0.30.4plain-crypto-js
三个都没有?大概率安全。后面几步也值得做。
第二步:清缓存
bash
npm cache clean --force
踩坑预警:CI 环境也要清。 GitHub Actions、GitLab CI 的 node_modules 缓存和 npm 缓存里如果残留了恶意 tarball,下次构建还会命中。别只清本地。
第三步:锁死版本
json
"axios": "1.14.0"
注意是 "1.14.0",不是 "^1.14.0"。^ 意味着自动升级到最新兼容版本,这次恰恰是这个机制让恶意版本被装上的。恶意版本虽然已经下架,但显式锁定是个好习惯。
第四步:审计 install 脚本
bash
grep -r '"postinstall"' node_modules/*/package.json
这次的载体就是 postinstall。顺手看看你其他依赖有没有可疑的 install 脚本。
激进做法:.npmrc 里加 ignore-scripts=true,全局禁止。但 esbuild、sharp 这些包也靠 postinstall 下载二进制,全禁可能影响构建,自己权衡。
第五步:确认中招了?当作机器已经失控处理
不是"可能要换密码"。是现在就轮换所有凭证:
- npm token
- GitHub token
- SSH key
- 数据库密码
- 云服务 AK/SK
CI 机器中招的话,检查 CI secrets 是否泄露。
查异常进程和网络连接,关注 sfrclak.com:8000 这个地址。
RAT 跑起来之后,你机器上的一切对攻击者都是透明的。别侥幸。
大包不等于安全
很多开发者的直觉是:axios 每周 1 亿下载,总不会出事吧。反过来想,越热门的包,攻击者的投入产出比越高。投毒一个每周 100 下载的包没人在乎,投毒一个每周 1 亿下载的包,3 小时窗口就够覆盖成千上万个项目。
这次 axios 的源码没有任何问题。
问题出在发布链上。你默认信任的那条从代码到 registry 的链路,才是该被审计的东西。lockfile 锁版本,审计 install 脚本,监控依赖变更,关注 registry 元数据的发布者签名。不是有空再搞的事。
你的项目查了吗?评论区报个平安。身边有用 axios 的朋友还不知道这事的,转给他看一眼。