首页 >> 分享>>Javascript>>npm Shai-Hulud 沙虫投毒:AntV 生态大规模中招,你的项目安全吗?
npm Shai-Hulud 沙虫投毒:AntV 生态大规模中招,你的项目安全吗?

2026 年 5 月 19 日,一场迄今规模最大的 npm 供应链攻击悄然发生。攻击者在 22 分钟内发布了 639 个恶意包版本,覆盖整个 AntV 可视化生态及数十个周边包,涉及每周下载量合计超过 1600 万次的项目。
事件背景
AntV 是阿里巴巴旗下的开源数据可视化套件,旗下包含 @antv/g2、@antv/g6、@antv/l7、@antv/s2 等超过 100 个 npm 包,广泛用于企业级数据大屏、图分析、地理可视化等场景。
此次攻击被安全研究团队命名为 Mini Shai-Hulud(沙虫,出自科幻小说《沙丘》),是同系列攻击活动的最新一波。攻击者通过盗取 AntV 维护者的 npm 账号凭证,以”官方身份”发布了携带恶意代码的新版本。
攻击入口:一个被盗的 npm 账号
被攻陷的账号是 atool(注册邮箱 i@hust.cc),这是 AntV 团队的真实维护者账号,同时也是 timeago.js、size-sensor、echarts-for-react 等多个热门包的发布者,名下共维护 547 个 npm 包。
攻击者通过社会工程学或凭证窃取的方式拿到了该账号的 npm 发布 token,随后在短短 22 分钟内以自动化脚本批量发布恶意版本。由于用的是真实账号,npm 平台无法区分合法发布与恶意发布。
攻击手法:preinstall 钩子植入恶意载荷
每个被污染的包都做了同样的改动:
1. 在 package.json 中注入 preinstall 钩子
{
"scripts": {
"preinstall": "bun run index.js"
}
}
只要执行 npm install,这段脚本就会自动静默运行,无需任何用户确认。
2. 植入高度混淆的恶意脚本 index.js
文件体积约 500KB,单行压缩,使用大型字符串查找表、运行时解码和自定义解密器进行混淆,肉眼无法识别其功能。
3. 附加一个指向 GitHub commit hash 的可选依赖
作为二级载荷分发渠道,进一步扩大攻击面。
恶意代码会做什么
载荷运行后,会从以下渠道系统性地窃取凭证:
读取环境变量
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
GITHUB_TOKEN / NPM_TOKEN
各类 CI/CD 平台注入的 secret
读取本地配置文件(覆盖 130+ 个路径)
~/.aws/credentials # AWS 凭证
~/.ssh/id_rsa # SSH 私钥
~/.npmrc # npm token
~/.kube/config # Kubernetes 配置
~/.config/gcloud/ # Google Cloud
加密货币钱包文件
浏览器存储数据
shell 历史文件
读取 GitHub Actions runner 进程内存
这是最隐蔽的部分。GitHub Actions 的 secret 在日志中显示为 ***,但在 runner 进程的内存中是明文的。恶意脚本通过读取 /proc/<pid>/mem 直接扫描 runner 进程内存,将所有被遮盖的 secret 还原成明文。
请求云平台元数据接口
在 AWS EC2 实例中,以下地址无需认证即可访问:
http://169.254.169.254/latest/meta-data/iam/security-credentials/
可直接获取 IAM 临时凭证。
数据外传渠道
窃取的数据通过两条渠道上传:
- 主渠道:写入
antvis/G2仓库的 GitHub API(dead-drop 技术,混在正常 GitHub 流量中) - 备用 C2:
t.m-kosche.com:443,伪装成 OpenTelemetry 收集器端点
持久化后门
载荷还会在 Claude Code 和 VS Code 的配置目录中植入后门,在会话重启后依然存活。
蠕虫特性:用偷来的 token 继续传播
这次攻击不只是窃取,还会主动利用窃取到的凭证。
截至事件披露,攻击者已用偷来的 GitHub token 创建了超过 2200 个公开 GitHub 仓库,仓库名称均来自《沙丘》宇宙术语,描述为反转字符串 niagA oG eW ereH :duluH-iahS(正读为 Shai-Hulud: Here We Go Again)。
这使得攻击的爆炸半径可以被实时观测,也证明了被盗凭证正在被积极用于构建后续攻击基础设施。
受影响的包(部分)
以下为已确认的被污染包及对应恶意版本:
| 包名 | 恶意版本 |
|---|---|
echarts-for-react | 3.0.7, 3.1.7, 3.2.7 |
timeago.js | 4.1.2, 4.2.2 |
size-sensor | 1.0.4, 1.1.4, 1.2.4 |
jest-canvas-mock | 2.5.3, 2.6.3, 2.7.3 |
canvas-nest.js | 2.1.4, 2.2.4 |
@antv/g2 | 5.5.8, 5.6.8 |
@antv/g6 | 5.2.1, 5.3.1 |
@antv/g | 6.4.1, 6.5.1 |
@antv/l7 | 2.26.10, 2.27.10 |
@antv/s2 | 2.8.1, 2.9.1 |
@antv/x6 | 3.2.7, 3.3.7 |
@antv/f2 | 5.15.0, 5.16.0 |
@antv/g2plot | 2.5.35, 2.6.35 |
@antv/graphin | 3.1.5, 3.2.5 |
@antv/data-set | 0.12.8, 0.13.8 |
mcp-echarts | 0.8.1, 0.9.1 |
lint-md | 0.3.0, 0.4.0 |
完整列表持续更新,可查阅:https://socket.dev/supply-chain-attacks/mini-shai-hulud
如何判断自己是否中招
检查 lockfile 中的版本
查看你的 package-lock.json 或 yarn.lock,确认是否包含上述任意恶意版本。重点排查 2026 年 5 月 19 日 01:39 ~ 02:18 UTC 之间发布的版本。
# 快速检查 echarts-for-react 版本
cat package-lock.json | grep -A2 '"echarts-for-react"'
如果安装了恶意版本
立即假设该环境中所有可访问的凭证均已泄露,需要:
- 轮换所有 AWS / GCP / Azure 密钥
- 重置 GitHub token 和 npm token
- 轮换 Kubernetes service account
- 检查 SSH 私钥是否需要更换
- 审查 CI/CD pipeline 的 secret 配置
如何防御此类攻击
1. 使用 lockfile + npm ci
有 lockfile 且不升级依赖,是最有效的防护手段。CI 环境应始终使用 npm ci 而非 npm install,前者严格按照 lockfile 安装,不允许任何版本漂移。
# CI 环境推荐
npm ci
# 而不是
npm install
2. 关闭自动依赖升级
Dependabot、Renovate 等工具会自动升级依赖并提 PR,在升级 PR 合并前务必审查版本变更,不要无脑合并。
3. npm 账号开启 MFA
维护者账号必须开启多因素认证,这是防止账号被盗的第一道门。
4. 使用私有 registry 并配置冷却期
自建私有 npm 库(如 Verdaccio、Nexus)并配置新版本冷却窗口,新发布的版本经过一段时间校验后再开放使用,可有效阻断此类攻击的即时传播。
5. 禁用 postinstall / preinstall 钩子(高风险环境)
npm ci --ignore-scripts
在 CI 环境中可以考虑忽略安装脚本,但需注意部分合法包也依赖这些钩子(如 node-gyp 编译原生模块)。
总结
这次攻击的可怕之处不在于技术多复杂,而在于它利用了开发者对**”官方账号发布”的天然信任**。攻击者不需要破解任何加密,只需要一个被盗的 token,就可以向数百万开发者的机器发送任意代码。
供应链安全的核心矛盾是:开源生态的便利性建立在信任之上,而信任本身就是最大的攻击面。
锁版本、用 npm ci、开 MFA,这三件事做到,可以抵御绝大多数此类攻击。
参考来源:StepSecurity、Socket、Snyk、JFrog Security Research
发表评论