binding.gyp:一次像蠕虫一样传播的 npm 供应链攻击

一种自我复制的蠕虫正在通过 binding.gyp 在 npm 注册表中传播。该文件会在 npm install 期间触发代码执行,而无需触及 package.json 中的 scripts。该攻击绕过了传统安全工具,已成功入侵跨多个维护者账户的数十个软件包。

这是一起正在发展中的安全事件。​ StepSecurity 正在积极调查此次供应链攻击。我们持续识别其他被入侵的软件包,并将随着新信息的出现而更新本文。

摘要

StepSecurity 已识别出一种活跃的自我复制供应链攻击,正在 npm 注册表中传播。该攻击使用了一种我们此前未曾在此规模上见过的技术:攻击者并非依赖 package.json 生命周期钩子(如 preinstallpostinstall,安全工具通常会标记这些),而是注入了一个 binding.gyp 文件,导致 npminstall 过程中静默执行恶意代码。

该恶意软件是一个完整的 CI/CD 蠕虫。一旦在开发者的环境或 CI 管道中运行,它会从 npm、GitHub、AWS、GCP、Azure、HashiCorp Vault、Kubernetes 和 RubyGems 中收集凭据。然后利用这些凭据发布受害者维护的其他软件包的有毒版本,将自身进一步传播到生态系统中。它还会在 GitHub Actions 工作流中注入恶意步骤,确保在受影响仓库的每个未来 CI 作业中运行。

到目前为止,StepSecurity 已识别出多个 npm 软件包中被入侵的版本。随着蠕虫的传播,该列表持续增长。

该攻击的特殊之处:binding.gyp 技术

大多数 npm 供应链攻击会将恶意代码注入 package.jsonpreinstallpostinstall 脚本中。安全工具、代码审查者和 npm 自身的审计系统都高度关注这些钩子。

攻击者完全绕过了这些防护措施。他们向软件包添加了一个小的 binding.gyp 文件。当 npm 检测到 binding.gyp 时,它会自动调用 node-gyp 来编译它假设的原生插件。攻击者利用 node-gyp 的 shell 扩展功能,在 install 命令数组中执行任意代码:

__CF_CODE_BLOCK_0__

这会在安装过程中静默运行 node-gyp。软件包的 package.json scripts 部分仅包含合法的构建命令。没有 postinstall 钩子来引起怀疑。binding.gyp 文件仅有 100 字节。然而,它触发的恶意 node-gyp install 脚本却是 4.5 至 4.9 MB 的混淆代码。

攻击原理

恶意软件分三个阶段执行:

阶段 1:混淆加载器。​ 根级 binding.gyp 使用 ROT-N 凯撒密码解码内部脚本,然后使用硬编码密钥解密两个 AES-128-GCM 加密的有效载荷。

阶段 2:运行时下载。​ 第一个解密的有效载荷静默将 Bun JavaScript 运行时(v1.3.13)从 GitHub 下载到临时目录。这为攻击者提供了一个快速的独立运行时,避免在 Node.js 进程树中留下明显的痕迹。

阶段 3:CI/CD 蠕虫。​ 第二个解密的有效载荷(约 720 KB)是主要的蠕虫。它通过下载的 Bun 运行时运行,并执行四项操作:

  1. 凭据收集。​ 它扫描环境中的 npm 令牌、GitHub 令牌和 PAT、AWS 访问密钥(包括 IMDSv2 和 ECS 任务角色端点)、GCP 服务账户凭据、Azure 客户端密钥和 Key Vault 内容、HashiCorp Vault 令牌(检查多个文件路径和本地 Vault API)、Kubernetes 服务账户令牌、RubyGems API 密钥,以及来自 1Password CLI、gopass 和 pass 的密码。它还从 GitHub Actions 运行器进程内存中提取掩码的秘密。
  2. GitHub Actions 工作流注入。​ 使用窃取的 GitHub 令牌,蠕虫修改受害者可以推送到的仓库中的 CI/CD 工作流文件。它注入一个 actions/checkout 步骤和一个有效载荷执行步骤,确保蠕虫在每个未来的 CI 作业中运行。
  3. 软件包投毒。​ 使用窃取的 npm 或 RubyGems 令牌,蠕虫查询注册表获取受害者维护的所有软件包,下载它们,注入恶意有效载荷,并发布新的有毒版本。这就是蠕虫如何从一个被入侵账户传播到数十个软件包。
  4. 泄露。​ 窃取的凭据使用硬编码的 RSA 公钥加密,并作为"悬空提交"(无法从任何分支到达的提交)泄露到攻击者控制的 GitHub 仓库,使其难以通过正常的仓库浏览发现。

受影响的软件包

以下表格列出了截至目前已确认的所有被入侵的软件包及版本。均在 2026 年 6 月 3 日至 6 月 4 日期间发布。​此列表会随着我们识别更多受影响的软件包而持续更新。​

Package

Malicious Versions

@evolvconsulting/evolv-coder-lite

1.2.0

@jagreehal/workflow

1.16.1

@vapi-ai/server-sdk

0.11.1, 0.11.2, 1.2.1, 1.2.2

ai-sdk-ollama

0.13.1, 1.1.1, 2.2.1, 3.8.5

autotel

2.26.4, 3.4.3

autotel-adapters

0.3.5

autotel-audit

0.1.15

autotel-aws

0.13.10

autotel-backends

2.12.26

autotel-cli

0.8.14

autotel-cloudflare

2.18.16

autotel-devtools

0.1.1, 1.0.4, 2.1.1, 3.0.2, 4.0.1, 5.1.1, 6.1.2

autotel-drizzle

0.0.27

autotel-edge

3.16.13

autotel-eventcatalog

1.0.1, 2.0.1, 3.0.1, 4.0.2, 5.0.1

autotel-hono

0.4.26

autotel-mcp

0.1.14, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.1, 17.0.2, 18.0.1, 19.0.1, 20.0.1, 21.1.1, 22.0.1, 23.0.1, 24.0.1, 25.0.1, 26.0.2, 27.0.1, 28.0.3

autotel-mcp-instrumentation

29.0.2, 30.0.5, 31.0.1, 32.0.1, 33.0.2, 34.0.1

autotel-mongoose

0.0.3, 1.0.2, 2.0.5, 3.0.1, 4.0.1, 5.0.2, 6.0.1

autotel-pact

0.2.2, 1.0.3

autotel-playwright

0.4.32

autotel-plugins

0.19.26

autotel-sentry

0.5.13

autotel-subscribers

4.1.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.1.1, 15.0.1, 16.0.2, 17.0.1, 18.0.3, 19.0.1, 20.0.1, 21.0.1, 22.0.2, 23.0.2, 24.0.1, 25.0.1, 26.0.1, 27.0.2, 28.0.2, 29.0.6, 30.0.4, 31.1.4

autotel-tanstack

1.13.27

autotel-terminal

2.1.1, 3.0.1, 4.0.2, 5.0.1, 6.0.3, 7.0.1, 8.0.1, 9.0.1, 10.0.2, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.2, 17.0.10, 18.0.4, 19.0.8, 20.0.2, 21.0.1, 22.0.2, 23.0.3

autotel-vitest

0.4.26

autotel-web

1.12.2

awaitly

1.33.3

awaitly-analyze

0.24.2, 1.1.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1

awaitly-libsql

0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.1, 21.0.1, 22.0.1

awaitly-mongo

0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.1.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1

awaitly-postgres

0.1.1, 1.0.1, 2.0.1, 3.0.2, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1

awaitly-visualizer

1.0.1, 2.0.2, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.2, 21.0.1, 22.0.2

effect-analyzer

0.3.1

eslint-plugin-awaitly

0.17.1, 1.0.1

eslint-plugin-executable-stories-jest

1.2.1, 2.1.8

eslint-plugin-executable-stories-playwright

1.2.1, 2.1.8

eslint-plugin-executable-stories-vitest

1.2.1, 2.1.8

executable-stories-cypress

3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.2

executable-stories-demo

0.1.11

executable-stories-formatters

0.11.2

executable-stories-init

0.1.2

executable-stories-jest

3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.2

executable-stories-mcp

0.3.3

executable-stories-playwright

3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.4.3

executable-stories-react

0.1.7

executable-stories-vitest

2.0.1, 3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.3

http-uploader-dev

1.0.7

mountly

0.2.2

mountly-tailwind

0.1.3

node-env-resolver

6.5.1

node-env-resolver-aws

9.1.2, 10.0.1, 11.0.1, 12.0.1

node-env-resolver-dotenvx

1.0.1, 2.0.1

node-env-resolver-nextjs

7.4.2

node-env-resolver-vite

2.4.2

wrangler-deploy

1.5.5