用于检测TanStack npm供应链攻击指标的Shell脚本 (CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx)
检测开发者机器、仓库或CI运行器上TanStack npm供应链攻击的指标。提供Bash脚本、Docker镜像和GitHub Action三种入口,共享同一检测引擎。
CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx
2026年5月11日,攻击者通过GitHub Actions缓存投毒,在42个@tanstack/*包中发布了84个恶意版本。该载荷窃取GitHub令牌、npm令牌、AWS/GCP/Azure凭证,并安装了一个死亡开关守护进程,一旦被窃取的令牌被撤销,就会立即清空~/目录。
选择与你当前环境匹配的入口。
TAG=v1.0.0
curl -fsSLO https://github.com/fabriziosalmi/tanstack-compromise-checker/releases/download/$TAG/check.sh
curl -fsSLO https://github.com/fabriziosalmi/tanstack-compromise-checker/releases/download/$TAG/check.sh.sha256
sha256sum -c check.sh.sha256
bash check.sh --online
docker run --rm -v "$PWD":/scan \
ghcr.io/fabriziosalmi/tanstack-compromise-checker:v1.0.0 \
/scan true fail tanstack-findings.json '' GHSA-g7cv-rxg3-hmpx
该镜像支持多架构(linux/amd64、linux/arm64),并附带通过GitHub OIDC签名的构建来源证明。运行前请验证:
gh attestation verify \
oci://ghcr.io/fabriziosalmi/tanstack-compromise-checker:v1.0.0 \
--repo fabriziosalmi/tanstack-compromise-checker
permissions: {}
jobs:
check:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: fabriziosalmi/tanstack-compromise-checker@v1
with:
scan-dir: .
online: 'true'
fail-on: fail
一个完整的加固工作流位于.github/workflows/tanstack-check.yml,该仓库自身也使用同一工作流进行自检。
使用--online时,脚本还会在运行时获取GHSA公告,从而使检测覆盖范围与公告的实时状态保持一致,而非使用硬编码的版本列表。
受影响系列:@tanstack/router、@tanstack/react-router、@tanstack/history、@tanstack/start、@tanstack/eslint-plugin-router及相关包。
未受影响系列(不受影响):@tanstack/react-query、@tanstack/react-table、@tanstack/react-virtual、@tanstack/form、@tanstack/store。
# 快速检查(当前用户的家目录)
bash check.sh
# 在线模式:查询GHSA公告和npm注册表发布时间
bash check.sh --online
# 扫描特定目录
bash check.sh --scan-dir /path/to/your/repos
# JSON输出,用于CI/SIEM集成
bash check.sh --json > findings.json
# 为受影响的仓库建议固定版本命令(试运行)
bash check.sh --scan-dir /path/to/repos --fix
# 提供扩展的已知恶意版本列表
bash check.sh --bad-versions-file ./extra-bad-versions.txt
| 码值 | 含义 |
|---|---|
| 0 | 干净——扫描范围内未发现指标 |
| 1 | 仅警告——建议审查 |
| 2 | 失败——存在入侵指标 |
| 3 | 工具/使用错误 |
该仓库针对自身检测的同类攻击进行了防御。具体来说:
uses:都固定到40个字符的提交SHA,而非浮动标签。permissions: {};作业仅授予所需权限。actions/checkout以persist-credentials: false调用,确保$GITHUB_WORKSPACE中不留已认证的git远程。step-security/harden-runner是每个工作流的第一个步骤,监控运行器出口流量。main时运行;结果以SARIF格式上传。gh attestation验证。check.sh.sha256涵盖所有可安装制品。完整策略见SECURITY.md。
不要对任何安全工具(包括本工具)使用curl | bash。始终先下载、验证校验和、检查,然后再运行。
━━ 1 / 8 死亡开关制品
✔ 未发现死亡开关制品
━━ 2 / 8 持久化向量
✔ 未检测到持久化向量
━━ 3 / 8 令牌/凭证暴露
✔ 未检测到凭证暴露
━━ 4 / 8 网络指标
✔ 当前未建立node TCP连接(或无法观察到)
━━ 5 / 8 仓库扫描 — package.json + lockfiles
ℹ 发现12个package.json + 8个lockfile
✔ 任何package.json中未声明受影响的系列
✔ 任何lockfile中未发现受影响的固定版本
━━ 6 / 8 已安装的node_modules — 直接版本检查
✔ 已安装的node_modules中未发现受影响的包
━━ 7 / 8 GitHub Actions加固提示
✔ 未检测到有风险的GitHub Actions模式(在扫描范围内)
━━ 8 / 8 Mini Shai-Hulud载荷 + 辅助IOC
✔ 未检测到Mini Shai-Hulud载荷/辅助IOC
━━ 摘要
通过:8 警告:0 失败:0
范围 : /Users/alice/dev
✔ 范围内无入侵指标:/Users/alice/dev
注意:/Users/alice/dev的干净结果不保证系统其他部分的安全。
在停止守护进程之前,不要撤销你的GitHub令牌——一旦令牌被撤销,死亡开关将执行
rm -rf ~/。
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.user.gh-token-monitor.plistlaunchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plistsystemctl --user stop gh-token-monitor && systemctl --user disable gh-token-monitorrm -f ~/.local/bin/gh-token-monitor.sh~/.aws/credentials、~/.kube/config、~/.config/gh/hosts.yml、~/.npmrc。Bash脚本需要:
bash 4+jq(推荐)——解析package-lock.jsonpython3(可选回退)——当jq不可用时使用curl——--online必需lsof或ss(可选)——网络IOC启发式Docker镜像已捆绑上述所有工具。在无法或不想安装这些工具的系统上使用它。
欢迎提交Issue和Pull Request。请注意,该仓库使用了CODEOWNERS:所有PR都需要维护者审查。
MIT.
| # | 检查项 | 描述 |
|---|
| 1 | 死亡开关 | ~/.local/bin/gh-token-monitor.sh,LaunchAgents + LaunchDaemons(macOS),systemd用户+系统单元(Linux),运行进程 |
| 2 | 持久化 | shell rc文件,用户/系统定时任务,/etc/cron.*,XDG自动启动,全局git core.hooksPath |
| 3 | 凭证 | 敏感环境变量,~/.npmrc,~/.yarnrc.yml,~/.aws/credentials,~/.config/gh/hosts.yml,~/.netrc,~/.docker/config.json,~/.kube/config,.env*文件枚举 |
| 4 | 网络IOC | 运行中的node进程,具有已建立的出站TCP连接(启发式,需人工审查) |
| 5 | 仓库扫描 | package.json声明的依赖 + lockfile固定的版本(package-lock.json,yarn.lock,pnpm-lock.yaml) |
| 6 | 已安装 | 检查node_modules/@tanstack/*/package.json,对照已知恶意版本列表,使用--online时再对照npm注册表的time[<version>] |
| 7 | Actions提示 | 扫描.github/workflows/*,查找pull_request_target、缺少--ignore-scripts、actions/cache的使用 |
| 8 | Mini Shai-Hulud IOCs | node_modules中的载荷文件(router_init.js、tanstack_runner.js),@tanstack/setup可选依赖,AI工具配置篡改,源代码中的C2域名,攻击者提交作者及分支模式,带赎金标记的npm令牌,二级蠕虫传播的包,以及未知载荷形状的信息级启发式检测 |
| 标志 | 描述 |
|---|
--scan-dir DIR | 要扫描的根目录(默认:$HOME)。拒绝扫描系统目录如/、/etc、/usr。 |
--online | 查询GHSA公告和npm注册表的time[<version>]以确认入侵。默认关闭——需主动启用。 |
--ghsa GHSA-ID | 覆盖--online中使用的公告ID(默认GHSA-g7cv-rxg3-hmpx)。 |
--attack-window-start ISO,--attack-window-end ISO | 覆盖--online中使用的发布时间窗口。 |
--fix | 打印受影响的仓库的建议固定版本命令(默认试运行)。 |
--apply | 与--fix结合:选择实际执行。目前仍拒绝盲目update;需要手动固定版本。 |
--yes,-y | 跳过--apply的确认提示。 |
--json | 以JSON格式将发现结果输出到stdout(隐含--quiet)。 |
--bad-versions-file F | 将条目(每行pkg@version)追加到已知恶意版本列表。 |
--no-color | 禁用ANSI颜色。 |
--quiet,-q | 抑制逐项检查输出,仅打印摘要。 |
-h,--help | 显示帮助信息。 |