TanStack npm 供应链攻击 — Mini Shai-Hulud 蠕虫回归
发布日期:2026-05-12 阅读时间:6 分钟 安全 / 供应链攻击
事件概述
2026年5月11日,一个名为 Mini Shai-Hulud 的自传播蠕虫攻破了 TanStack npm 生态系统。TanStack 是 React 生态中最广泛使用的路由库之一,每周下载量达数百万次。攻击者向 40 多个 @tanstack 包注入了 2.3MB 的混淆凭证窃取 payload,并通过劫持的 OIDC token 利用项目自身的 GitHub Actions 发布管线发布了恶意版本。
这次事件的历史意义在于:它是 首个携带有效 SLSA 来源证明的自传播 npm 蠕虫。这些恶意包看起来完全合法——因为它们确实是由真实管线发布的。蠕虫继承了 TanStack 的可信发布者身份。
攻击首先由 StepSecurity 通过其 OSS Package Security Feed 实时检测到并披露。GitHub Issue #7383 被创建以通知维护者,该事件迅速登上 Hacker News 首页。
攻击链详解
第一步:Fork 并准备载荷
攻击者于 2026年5月10日创建了 TanStack/router 的 Fork,推送了一个包含伪造 @tanstack/setup 包的 commit(79ac49ee)。该包的 prepare 生命周期钩子会运行 bun run tanstack_runner.js && exit 1 —— 末尾的 && exit 1 是故意的,让可选依赖"优雅地失败",在日志中留下极少痕迹,而此时 payload 已经执行完毕。
第二步:注入已发布的包
每个被投毒的包都被做了两处修改:
- 新增
optionalDependencies条目,通过github:URL 指向攻击者的 Fork commit - 在包根目录放置了一个
router_init.js文件(2.3MB)——位于正常的dist/和src/目录之外
结果:被投毒的 tarball 比正常版本大 3.7 倍(905 KB vs 190 KB),多出 23 个文件。
第三步:通过合法管线发布
恶意包携带了绑定到真实 TanStack Release 工作流的 有效 SLSA 来源证明。攻击者利用工作流的环境 id-token: write OIDC token 直接发布到 npm —— 绕过了工作流自身的发布步骤,即使"Run Tests"步骤已经失败。
Payload 分析:它窃取什么
router_init.js payload 使用了多层混淆:
- 十六进制变量名 —— 仅前 10KB 就有 163 个
_0x前缀的变量 - 字符串表轮转 —— 一个通过解析函数间接访问的大型编码字符串数组
- AES-256-GCM 加密 —— 敏感字符串(域名、路径、token 模式)在运行时通过
crypto模块解密
Payload 包含 10 个专用收集器类,从多个来源采集密钥。它读取 GitHub Actions 环境变量(GITHUB_WORKFLOW_REF、GITHUB_REPOSITORY 等)来识别高价值目标。它导入了 child_process、fs、crypto 和 os —— 赋予它任意命令执行、文件系统访问和加密签名能力。
窃取的凭证通过 HTTPS(443 端口)以缓冲调度系统发送到攻击者控制的服务器,包含多个备用发送通道。
自传播机制:蠕虫如何扩散
Mini Shai-Hulud 最危险的特性是 自主传播。收集到 token 后,蠕虫会遍历发现的 GitHub token,用它们来:
- 向 npm 注册表或 GitHub API 认证
- 识别该 token 有写权限的其他包
- 向这些包注入相同的恶意 payload
- 发布新的被投毒版本
这个传播循环解释了为什么攻击扩散到了 TanStack 之外的包——@uipath(8个包)、@draftauth、@draftlab、@taskflow-corp、@tolka 等——蠕虫跟着窃取到的凭证走到哪里就感染到哪里。
受影响的包(部分列表)
@tanstack 生态 —— react-router、router-core、react-start、solid-router、vue-router、history、router-plugin 等数十个。每个包都收到了两个被投毒的版本("双重打击"模式)。
其他组织 —— @uipath(8个包,包括 agent.sdk、filesystem、admin-tool)、@draftauth(client、core)、@draftlab(auth、auth-router、db)、@taskflow-corp/cli、@tolka/cli。
完整列表在 StepSecurity OSS Security Feed 持续更新。
我是否受影响?
检查你的 Lockfile
grep "@tanstack/" package-lock.json | grep -v node_modulesgrep -E "(draftlab|draftauth|taskflow-corp|tolka)" package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
将解析出的版本与 StepSecurity 列出的被投毒版本进行交叉比对。
检查恶意文件
find node_modules -name "router_init.js" -type f 2>/dev/nullgrep -r "@tanstack/setup" node_modules/*/package.json 2>/dev/null
检测信号
- 包根目录存在
router_init.js optionalDependencies指向带有特定 commit hash 的github:URL- 包体积异常:~900 KB vs 正常的 ~190 KB
npm install或构建步骤期间出现出站 HTTPS 连接
恢复步骤
个人开发者
- 锁定到安全版本 —— 降级到每个受影响包的最后一个干净版本
- 删除并重装 ——
rm -rf node_modules && npm install - 轮转凭证 —— 该机器上可访问的所有 npm token、GitHub PAT 和云 API 密钥
- 检查 ~/.npmrc —— 蠕虫会读取主目录密钥,审查并轮转存储的 token
CI/CD 环境(紧急)
- 立即轮转所有 CI 密钥 —— GitHub token、npm token、云服务商凭证及工作流环境中可访问的所有密钥
- 审计 GitHub Actions 运行记录 —— 审查 2026-05-11T19:20Z 之后的运行,查找意外的 npm publish 事件
- 检查下游传播 —— 如果你的任何包是在安装了被投毒版本的 CI 运行中发布的,那些版本可能也被感染了
- 审查 npm access token —— 运行
npm token list并撤销不认识的 token
如何防御 CI/CD 蠕虫攻击
- 在 CI 中给 npm install 加上
--ignore-scripts—— 只为已知依赖显式运行生命周期脚本 - 使用运行时 CI/CD 监控 —— StepSecurity Harden Runner 等工具可以检测并阻止构建期间的异常出站网络连接和未授权进程执行
- 验证包完整性 —— 使用
npm audit signatures,但记住有效来源证明不等于安全(本次攻击已证明这一点) - 限制 OIDC token 权限 —— 将
id-token: write限制在真正需要的步骤,而不是整个工作流 - 监控包体积变化 —— 3.7 倍的体积增长应触发自动告警
入侵指标(IoC)
SHA-256 哈希:
router_init.js:ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266ctanstack_runner.js:2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96
攻击者基础设施:
- GitHub 账号:
voicproducoes(ID: 269549300),创建于 2026-03-19 - Fork:
voicproducoes/router,创建于 2026-05-10 - 恶意 commit:
79ac49eedf774dd4b0cfa308722bc463cfe5885c - 蠕虫标记仓库:
siridar-ghola-567、tleilaxu-ornithopter-43
相关文章
- Obsidian 插件被滥用部署 PhantomPulse 远程访问木马 — 安全防护指南 2026
- AI Agent + MCP 安全清单:权限、审计与最小暴露
- ClaudeBleed:Claude Chrome 扩展漏洞泄漏对话数据
- cPanel Black Week:3 个新漏洞曝光 44,000 台服务器遭勒索攻击
- English Version: TanStack npm Supply Chain Attack — Mini Shai-Hulud Worm Returns
总结
Mini Shai-Hulud 攻击暴露了 npm 生态信任模型的根本缺陷。来源证明只能确认制品是在哪里构建的,无法确认构建了什么。一条攻破 CI/CD 管线的蠕虫会继承管线的全部身份——OIDC token、SLSA 签名、可信发布者状态。从注册表的角度看,恶意发布和合法发布完全无法区分。
关键要点:
- OIDC token 是新的王冠上的宝石 —— 保护 CI/CD 密钥不再是可选项
- SLSA 来源证明有必要但不够 —— 构建期间实际发生了什么的运行时可见性,比输出上的标签更重要
- 自传播蠕虫已经到来 —— npm 生态现在面临着利用窃取凭证在包之间跳跃的自主传播攻击
- 速度至关重要 —— StepSecurity 的实时检测是关键,没有它蠕虫可能传播得更远
来源:StepSecurity — Mini Shai-Hulud Is Back | GitHub Issue #7383 | Hacker News 讨论