@antv npm供应链攻击 — Mini Shai-Hulud 事件分析
事件概述
2026年5月19日,Socket 安全团队监测到 @antv 生态系统遭遇大规模 npm 供应链攻击。攻击者控制了 npm 维护者账户 atool,发布了 639 个恶意版本(涉及 323 个独立包),影响范围涵盖数据可视化、图表、地图、React 组件等多个生态。
受影响的核心包包括:@antv/g2、@antv/g6、@antv/x6、@antv/l7、@antv/s2、@antv/f2、@antv/g、@antv/g2plot、@antv/graphin、@antv/data-set,以及 echarts-for-react(周下载量约 110 万)、timeago.js、size-sensor、canvas-nest.js 等。
受影响版本
所有在 2026年5月19日 01:39~02:56 UTC 期间从 atool 账户发布的版本均为恶意。每个包通常有两个被投毒版本(多为 minor 版本号 +1 和 +2):
核心 @antv 包受影响的版本示例
| 包名 | 恶意版本 | 周下载量 |
|---|---|---|
@antv/g2 | 5.5.8, 5.6.8 | 354k |
@antv/g6 | 5.2.1, 5.3.1 | 1M+ |
@antv/g2plot | 2.5.35, 2.6.35 | 108k |
@antv/g | 6.4.1, 6.5.1 | - |
@antv/g6-core | 0.9.24, 0.10.24 | 70k |
@antv/s2 | - | - |
@antv/x6 | - | - |
@antv/l7 | - | - |
@antv/f2 | 5.15.0, 5.16.0 | - |
@antv/component | 2.2.11, 2.3.11 | - |
@antv/coord | 0.5.7, 0.6.7 | - |
@antv/attr | 0.4.5, 0.5.5 | 170k |
@antv/algorithm | 0.2.26, 0.3.26 | 199k |
@antv/adjust | 0.3.5, 0.4.5 | 144k |
@antv/scale | - | 2.2M/月 |
非 @antv 受影响包
| 包名 | 恶意版本 | 月下载量 |
|---|---|---|
size-sensor | 1.0.4 | 4.2M |
echarts-for-react | 3.0.7 | 3.8M |
timeago.js | - | 1.15M |
jest-canvas-mock | 2.5.3 | - |
jest-date-mock | 1.0.11 | - |
amapcn | 0.1.2, 0.2.2, 0.3.2 | - |
检测方法:检查 lockfile 中
atool账户维护的任一包的 resolved 版本是否在 2026-05-19 01:39~02:56 UTC 之间发布。参考 OSV 通报:MAL-2026-3845、MAL-2026-3859、MAL-2026-3982等约 317 个MAL-2026-*条目覆盖本次攻击。
攻击时间线
| 时间(UTC) | 事件 |
|---|---|
| 01:56 | 恶意发布活动开始 |
| 02:02 | Socket 检测到首批恶意包 |
| 02:56 | 恶意发布活动结束 |
| 03:09 | 最后一批检测确认 |
检测中位时间约 6.7 分钟。
全战役统计
| 生态 | 恶意版本 | 独立包数 |
|---|---|---|
| npm | 1,048 | 498 |
| PyPI | 6 | 3 |
| Composer | 1 | 1 |
| 总计 | 1,055 | 502 |
技术分析
恶意载荷结构
攻击者在包的根目录注入 index.js,并在 package.json 中添加安装时钩子:
{
"scripts": {
"preinstall": "bun run index.js"
},
"optionalDependencies": {
"@antv/setup": "github:antvis/G2#1916faa365f2788b6e193514872d51a242876569"
}
}混淆手法
index.js 高度混淆,使用大字符串数组查表、运行时字符串解码,通过 globalThis 暴露自定义解密函数 fc2edea72。与既往 Mini Shai-Hulud 变种一致。
数据外泄
- C2 端点:
https://t.m-kosche.com:443/api/public/otel/v1/traces - 加密方式:数据经 gzip 压缩 → AES-256-GCM 加密 → AES 密钥经 RSA-OAEP/SHA-256 包装
- 攻击者难以从网络流量中恢复明文
窃取目标
- GitHub Token(
GITHUB_TOKEN、ACTIONS_ID_TOKEN_*) - AWS 凭证(
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY等) - Kubernetes 服务账户凭证(
KUBECONFIG、KUBERNETES_SERVICE_HOST) - Vault Token(
VAULT_ADDR、VAULT_TOKEN等) - SSH 私钥、Docker 认证文件、数据库连接字符串
CI/CD 平台检测逻辑
GitHub Actions、GitLab CI、Travis CI、CircleCI、Jenkins、Azure DevOps、AWS CodeBuild、Buildkite、AppVeyor、Bitbucket Pipelines、Drone、Semaphore、TeamCity、Bamboo、Bitrise、Vercel、Netlify、Cloudflare Pages
GitHub 备用外泄通道
若获取到有效 GitHub Token,载荷会在受害者账号下创建仓库,将窃取数据提交至 results/results-<timestamp>-<counter>.json。
仓库名遵循模式:<dune词>-<dune词>-<3位数字>,README 中包含逆向标记 niagA oG eW ereH :duluH-iahS(反转后为 Shai-Hulud: Here We Go Again)。
已观测到的仓库名举例:
sayyadina-stillsuit-852atreides-ornithopter-112harkonnen-phibian-552fremen-fedaykin-225kanly-lasgun-874
npm 蠕虫式传播
载荷包含 npm 注册表滥用逻辑:
- 验证 npm Token 有效性
- 枚举 Token 拥有者可维护的包
- 下载包 tarball
- 注入恶意载荷 +
preinstall钩子 - 升级版本号
- 以维护者身份重新发布
IOC(入侵指标)
网络指标
t.m-kosche.comhttps://t.m-kosche.com:443/api/public/otel/v1/traces
检测线索(合法端点,非恶意设施)
以下为正常 npm/sigstore 服务端点,但在非发布环境的 CI/安装脚本中出现时需警惕:
https://registry.npmjs.org/-/npm/v1/tokenshttps://registry.npmjs.org/-/whoamihttps://registry.npmjs.org/-/v1/search?text=maintainer:<user>&size=250https://fulcio.sigstore.dev/api/v2/signingCerthttps://rekor.sigstore.dev/api/v1/log/entries
GitHub 标记
niagA oG eW ereH :duluH-iahSShai-Hulud: Here We Go Againresults/results-*.json
防御建议
- 锁定依赖版本,避免自动更新
- 使用
npm audit/ Socket 等工具扫描依赖 - 限制 CI/CD 环境中的 Token 权限
- 监控 npm 生命周期脚本执行
- 定期轮换 npm publish Token
