npm 包被投毒:一次 postinstall 能带走多少凭证
2026 年 10 月,tensorlake 的 0.5.144 被植入 Shai-Hulud 蠕虫,目标是 npm、GitHub、云厂商与 AI 服务的凭证。供应链攻击的门槛,已经低到一次账号失守。
装一个依赖,就等于把发布者的账号安全一起装进来。10 月 7 日,TypeScript SDK tensorlake 的 0.5.144 被确认携带 Shai-Hulud 凭证窃取蠕虫;0.5.143 及更早的版本被报告为干净。
时间线
StepSecurity 的复盘给出了相当精确的坐标:首个恶意提交在 2026-10-07 01:20 UTC 进入 tensorlakeai/tensorlake 的 main 分支,用的是一位维护者的名义。随后数小时内又跟了 7 次提交,逐步调整载荷,并往 package.json 里加了一条 preinstall 指令。
值得注意的是节奏:不是一次注入就收手,而是有人盯着结果改。这更像一次持续作业,而不是脚本撞库。
载荷盯上了什么
被窃取的目标列表基本覆盖了现代开发者的全部家当:
- npm 与 GitHub 令牌
- 云厂商密钥
- SSH 密钥
- Vault 与 Kubernetes 凭证
- 浏览器登录信息
- AI 工具配置
其中「AI 工具配置」这一项值得单独看。过去这类蠕虫只关心 CI 与云,现在它开始关心你本机上那些能直接调用大模型的 key——那东西没有配额告警,也没有审计日志,被拿走很久都不会有人发现。
为什么 provenance 挡不住
npm provenance 只能证明「这个包是从哪个仓库、哪个提交构建出来的」,它证明的是构建来源,不是源码内容。
这次的入口恰恰是维护者账号本身。构建链条上每一环都是真的:真的仓库、真的提交、真的 CI。供应链攻击早就不在「伪造来源」这一层打了,它在「来源本身被借用」这一层。
provenance 解决的是「这包是谁建的」,不解决「建它的人还是不是原来那个人」。
清理时最容易踩的坑
一个反直觉的细节:载荷里带了令牌监视器,如果先吊销被盗的 GitHub 令牌、再移除监视器,监视器可能直接清空 home 目录。
也就是说,标准应急动作(第一时间吊销凭证)在这里反而会触发数据损失。这不是让人别吊销,而是说明一件事:清理顺序本身是需要情报的,不能只靠肌肉记忆。
我的判断
对个人项目,我不打算上什么复杂的供应链防御。真正能落地的只有三条:
- 锁文件进版本库,并且认真看 diff——
package-lock.json里多出一个preinstall是能被看见的; - 别在开发机上放长期有效的云凭证,能用短期令牌就用短期;
- 装新依赖时,
npm install --ignore-scripts至少能挡住这一类。
第三条有个明确的代价:有些包真的需要构建步骤,忽略脚本会装不上。但「装不上」是个能立刻发现的问题,「装上了但被偷了」不是。

评论
…