FITURE

If you can fight, fight.

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

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

Posted by fiture / 2026年05月25日 / Javascript

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.jssize-sensorecharts-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 流量中)
  • 备用 C2t.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-react3.0.7, 3.1.7, 3.2.7
timeago.js4.1.2, 4.2.2
size-sensor1.0.4, 1.1.4, 1.2.4
jest-canvas-mock2.5.3, 2.6.3, 2.7.3
canvas-nest.js2.1.4, 2.2.4
@antv/g25.5.8, 5.6.8
@antv/g65.2.1, 5.3.1
@antv/g6.4.1, 6.5.1
@antv/l72.26.10, 2.27.10
@antv/s22.8.1, 2.9.1
@antv/x63.2.7, 3.3.7
@antv/f25.15.0, 5.16.0
@antv/g2plot2.5.35, 2.6.35
@antv/graphin3.1.5, 3.2.5
@antv/data-set0.12.8, 0.13.8
mcp-echarts0.8.1, 0.9.1
lint-md0.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

发表评论

电子邮件地址不会被公开。 必填项已用*标注