一幅在深海军蓝背景上生成的抽象插画:一串彼此咬合的半透明方块从左向右延伸,每个方块上都印有一枚微微发光的小型青色印章。在这串方块的中间附近,其中一个方块已被替换为一个深色方块,上面带有完全相同的青色印章,而整串方块仍毫无间断地继续延伸。细细的琥珀色丝线从那个深色方块向下分叉,伸向画面底部的一小排深色终端窗格。画面中不出现任何文字、数字、人物、品牌标识或组织标志。OrcaRouter 的标志合成在右下角。
AI Safety Incidents

ChainDrop:400+ 个 npm 包中具备有效来源证明,以及无需 npm install 的 Claude Code 钩子

作者

Elias Hawthorne

发布日期

最新模型 · 20查看全部模型 →
基准测试:Artificial Analysis · 每日更新
返回全部文章

在2026年8月4日,攻击者接管了keyv 背后的 GitHub 账户,这是一个缓存库,Elastic Security Labs 称其上个月下载量超过 6 亿次。Wiz Research 和 Orca Security 均记录,恶意文件被直接推送到 keyv 的主分支,随后该项目自己的 GitHub Actions 工作流构建并发布了被投毒的版本——因此它进入了 npm,并带有有效来源证明;供应链工具正是用这种证明来判定一个包是否可信。研究人员称为ChainDrop的自我传播蠕虫随后利用窃取的 npm 令牌,在其他维护者的包上故技重施:Elastic 截至8月6日统计到 400 多个不同的包,Microsoft Threat Intelligence 于8月4日描述了同一场活动,新加坡网络安全局统计到 1,300 多个受损包版本,合计月下载量达 20 亿次。Elastic 和 Microsoft 都描述了这样一种钩子:当仓库在Claude Code或Visual Studio Code中打开时会重新运行。该记录的完整来源列表、严重性等级和置信度评估位于AI 事件档案中,与同期归档的其他 npm 和开发者工具供应链条目并列在一起。

一个合法的发布流水线如何签署了自身的沦陷

Wiz Research 还原了事件最初几分钟的经过:从 8月4日 09:00 UTC 起,攻击者利用一个被盗用的身份,将 IDE 持久化载荷植入 keyv 仓库,随后不久便发布了包含该载荷的 keyv 新版本。Wiz 指出,被入侵的是一个 GitHub 维护者账号,并表示 keyv 与 cacheable 生态中的多个软件包也相继受到影响。

Orca Security 的快速响应报告对签名路径的描述更为具体。报告称,攻击者将两个恶意文件——setup.mjs 和 Math_Symbol.js——直接推送到主分支,并立即发布了新版本。由于这些版本是通过被入侵账户的 GitHub Actions 工作流构建的,被投毒的版本带着有效的来源签名发布到了 npm,从而绕过了标准的供应链完整性检查。Zscaler ThreatLabz 是一个独立研究团队,不在该记录所引用的来源之列,它得出了相同结论,并进一步给出了等级:恶意的keyv 6.0.0带有有效的SLSA Build Level 3来源证明,因为攻击者控制了源仓库。BleepingComputer 当天报道了此次攻击活动,记录了相同的机制——恶意文件被直接推送到各项目的主分支,生成了新版本,并且由于构建是通过合法的 GitHub Actions 工作流运行的,因此具有有效来源证明。

微软的分析补充了一个看似矛盾、实则不然的细节。在蠕虫的传播阶段,Microsoft Threat Intelligence 发现许多恶意版本没有对应的源代码提交、拉取请求、标签或合法发布,这表明攻击者直接修改并发布了包 tarball,而不是攻陷每个公共源代码仓库。综合来看,这些来源描述了同一场活动中的两种签名机制:最初的 keyv 发布版本经过受害者真实的 CI 流水线,并带有为其背书的证明;而蠕虫后来的发布版本则主要使用窃取的仓库令牌组装并发布,完全没有留下源代码踪迹。微软自己的观察是,直接发布 tarball 的模式解释了为什么恶意版本经常表现为普通的补丁版本号递增,却没有对应的源代码提交或拉取请求。

Zscaler直白地指出了这个令人不安的教训:来源验证的是构建过程,而不是账户的身份,也不是运行该过程的CI系统的完整性。它还承认了一个对任何重建该事件的人都至关重要的空白——在其分析之时,攻击者所使用的确切账户接管机制尚不清楚。

npm install 时会运行什么:preinstall、Bun 1.3.13,以及一个 300 种模式的收集器

Elastic Security Labs 将该触发器描述为 preinstall 钩子,位于 package.json 中;该钩子滥用了一项合法的 npm 功能,该功能会在软件包完成安装前运行任意命令,且无需受害者进行任何进一步交互。该钩子会启动 setup.mjs,后者检查 Bun JavaScript 运行时是否已存在。如果不存在,该投放器会检测机器的平台和架构,从官方发布页面下载 Bun v1.3.13,解压后用它执行有效载荷,然后删除临时目录以掩盖痕迹。Wiz 独立识别出用户代理 Bun/1.3.13 发出了这些恶意调用。该投放器是跨平台的,面向 Linux、macOS 和 Windows。

该载荷经过高度混淆,各来源对其大小的说法略有差异:Elastic 给出的数字是 711 千字节,Orca Security 给出的数字是 728 KB。它使用了控制流平坦化和 Base91 字符串编码方案,并带有《沙丘》主题字符串——laza、kanly、ghola、mentat、lasgun、sietch、fedaykin、tleilaxu、sandworm、sardaukar、ornithopter、navigator——Elastic 指出这与早期的 Shai-Hulud 活动有相似之处。

微软的行为描述补充了两个值得关注的细节。该载荷会先检查其环境,并在俄语系统上退出,避免出现重复实例,并在开发者工作站上启动一个分离的后台副本;在 CI 中,它会保持附着于当前活动任务,以便访问工作流机密、运行器凭据和 OpenID Connect 发布权限。

收集器正是这起事件成为 AI 工具链事件、而非普通凭据事件的关键所在。Elastic 表示,它会扫描 300 多种独特模式,覆盖开发者机器上的各类凭据存储,并且值得注意的针对目标是 AI 工具凭据:Anthropic、Claude、Codex、Cursor、OpenAI 和 Gemini。它还会获取 AWS、GCP、Azure 和阿里云凭据,GitHub 个人访问令牌,JWT 和会话令牌,HashiCorp Vault 令牌,SSH 私钥,Kubernetes 服务账户令牌以及 npm 令牌。Wiz 报告称,与其所基于的早期 Mini Shai-Hulud 代码相比,目标列表已扩大近 70%,新增内容包括 Claude、OpenAI、Codex、Cursor 和 Gemini 的 AI 代理凭据存储,Foundry、Solana 和 Monero 的加密货币密钥库,Jenkins 的 master.key,Argo CD 和 Harbor 密钥,阿里巴巴和腾讯 CLI 配置,以及 /etc/shadow。

Microsoft 和 Elastic 描述了相同的数据外传设计。结果会被序列化为 JSON、经 gzip 压缩,并使用随机生成的 AES-256-GCM 密钥加密,而该密钥则用攻击者的 RSA 公钥进行封装。该载荷不会硬编码其命令与控制域名:Elastic 表示,它会查询位于以下地址的以太坊智能合约:0xE1f2395ee43e45A1556EC6438a88c31B83493103,以在运行时获取当前端点,因此无需改动恶意软件即可轮换基础设施。如果这一方式失败,它会在 GitHub 提交历史中寻找一个带有密码学签名的标记——thebeautifulmarchoftime——并根据内嵌的 RSA 密钥验证该域名。如果两者都失败,它就会通过受害者自己账户创建的一个公开 GitHub 仓库进行外传,该仓库被描述为 "Shai-Hulud: Here We Go Again"。Microsoft 指出,其中一条回退路径会使用双重 Base64 对窃取的 GitHub 令牌进行编码,而不是对其进行加密。

传播取决于令牌质量。Elastic 报告称,只有当凭据扫描发现一个具有包写入权限并能够在没有双重认证的情况下发布的 npm 令牌时,该蠕虫才会激活;随后,它会下载每个可写包的最新 tarball,将自身注入其中,递增补丁版本并重新发布。BleepingComputer 补充说,每个令牌在被窃取之前,都会实时通过注册表的 whoami 端点进行验证。正是这套例行流程,将一个被盗用的身份变成了数百次发布,这也是恶意版本看起来像普通补丁版本递增的原因。

An HTML card titled 'The first four hours, 4 August 2026', subtitled 'What the sources put where in the infection order, and the three counts the campaign is quoted with'. A four-step numbered column headed 'Infection order' reads: 1, 09:00 UTC: files pushed to main — attacker adds IDE persistence payloads to the keyv repository, then publishes a new keyv version, per Wiz Research; 2, the victim's CI builds the payload — keyv 6.0.0 reaches npm through the compromised account's own GitHub Actions workflow carrying valid provenance and a SLSA Build Level 3 attestation, per Orca Security and Zscaler ThreatLabz; 3, the worm republishes with stolen tokens — stolen npm tokens with write access and 2FA bypass bump patch versions, at peak roughly one infected package per second, per Elastic Security Labs and Zscaler ThreatLabz; 4, IDE hooks travel with the repos — a stolen GitHub App token commits .claude/settings.json and .vscode/tasks.json to up to 50 branches per accessible repository, per Elastic Security Labs. A right-hand panel headed 'Three counts, three units' shows: 400+, unique npm packages compromised by 6 August, per Elastic and Microsoft Threat Intelligence; 868, worm-reached packages across 1,381 versions, per Aikido via BleepingComputer and Orca Security; 1,300+, package versions with 2 billion monthly downloads, per CSA Singapore advisory AD-2026-009, 6 August. A footer reads: each figure is a snapshot taken while the campaign was still running; none of the cited sources claims a final total.

无需 npm install 的感染路径

此次攻击活动与早期 npm 蠕虫的区别在于:安装已不再是唯一的入口。Elastic 描述了另外两条针对 AI 编程工具用户的执行路径。一个 SessionStart 钩子位于 .claude/settings.json,会在以下情况下运行 node .claude/setup.mjs:当新的 Claude 会话启动时。对于 VS Code,folderOpen 任务位于 .vscode/tasks.json,会在以下情况下运行 node .vscode/setup.mjs:当打开受感染的仓库时。微软的分析列出了同样的四个产物——.claude/settings.json、.claude/setup.mjs、.vscode/tasks.json 和 .vscode/setup.mjs——并将其描述为一种次要感染途径,可以在原始 npm 安装完成后重新启动载荷。

使这种情况大幅扩大的条件就在被盗凭据中。当GitHub App 令牌出现在其中时,Elastic 报告称该蠕虫会将恶意钩子提交到每个可访问仓库中最多 50 个分支,并向每个分支注入 .claude/settings.json 和 .vscode/tasks.json。Elastic 的结论是,开发者克隆其中一个分支并打开它后,仅打开项目就可能被感染——整个路径中无需安装软件包,因此也完全没有安装脚本防御。

Zscaler 的评估是:这些持久化钩子在软件包被移除后依然存活,而且只需在 VS Code 或 Claude Code 中打开该项目就会被重新执行,从而绕过了许多团队在早前的 npm 蠕虫事件后所采用的--ignore-scripts缓解措施。其建议也随之明确:应将 IDE 与 AI 智能体的配置文件——.claude/、.cursor/、.vscode/、.gemini/——视为可执行代码,并以与源代码同等的严谨程度进行审查。

针对攻击中涉及仓库的那一半,存在一个指纹特征。Elastic 报告称,蠕虫生成的提交可通过作者名 claude 和提交信息 chore: update config 识别,Wiz 也记录到了相同的提交信息字符串。Elastic 补充说,该提交信息还携带了被盗的 GitHub 令牌,以及一条恐吓性字符串——IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients——其将其解读为试图吓唬开发者不要撤销该令牌。Wiz 在初始提交中也记录到了同一字符串,而在引入 IDE 钩子的那些提交中则换成了较短的信息。

A generated abstract illustration on a deep navy field: a tall repository-shaped block stands at centre, its face divided into thin horizontal branch lines. A narrow beam of pale light from an editor-shaped pane at upper left falls across the block, and where the beam touches one branch line, a small bright hook symbol appears and a thin amber thread runs down into a dark pool at the base. The other branch lines remain untouched and faintly lit. No text, numbers, people, brand marks or organisation logos appear. The OrcaRouter logo is composited in the bottom-right corner.

计数并不一致,而这并不矛盾。

关于影响范围的每一个已公布数字都对应着不同的计量单位,而这些单位并不能互换。Elastic Security Labs 在 8 月 6 日的文章中统计出超过 400 个独立的 npm 软件包遭到入侵。Microsoft Threat Intelligence 则描述为超过 400 个软件包,分布于多个互不相关的发布者。据 BleepingComputer 引用,Aikido 给出的数字是至少 868 个软件包、涵盖 1,381 个版本。Orca Security 报告称,有 10 个被直接投毒的 keyv 和 cacheable 软件包,月下载量超过 6.19 亿次,随后又有868 个软件包和 1,381 个版本被该蠕虫波及,月安装量超过 20 亿次。新加坡 CSA 于 8 月 6 日发布的咨询公告 AD-2026-009 记录到超过 1,300 个遭入侵的软件包版本合计代表20 亿次月下载量。

这是三个不同的分母——软件包、软件包版本和月度下载量——取自一场仍在进行的活动的三个不同时刻。Zscaler 对速度的叙述解释了它们为何会不一致:它称该蠕虫在不到四小时内自我传播到 400 多个软件包,并且在高峰时,发布速度大约为每秒一个受感染软件包。把较晚的计数当作对较早计数的修正是不对的;每一次都只是一个快照,而且所引用的来源都没有声称一个最终总数。

Elastic 在库层面给出的暴露数据是被引用最多、也最不含糊的。它报告称,仅 keyv 上月下载量就超过 6 亿次,flat-cache 接近 5.8 亿次,cacheable-request 超过 1.37 亿次,cacheable 超过 3000 万次,cache-manager 超过 1600 万次。CSA 的公告列出了具体的受感染版本,其中包括 keyv 6.0.0、flat-cache 6.1.24、file-entry-cache 11.1.6、cacheable-request 13.0.20、cacheable 2.5.1、cache-manager 7.2.10、@cacheable/utils 2.5.1 和 ecto 5.0.1。

撤销陷阱

安装了受影响版本的响应人员在解决第一个问题后,又面临第二个问题。Elastic 报告称,在一个条件式 GitHub 回退路径中,载荷会尝试安装一个 token-monitor 组件,该组件用于维持凭据访问权限,并包含一个在受监控令牌被撤销时执行的破坏性处理程序。Zscaler 详细描述了该机制的实际运作方式,并将其称为令牌撤销陷阱:该蠕虫会使用窃取的令牌安装一个每 60 秒轮询 GitHub API 的后台进程;如果该令牌返回 4xx 错误——意味着受害者已将其撤销——则会触发一个次级破坏性载荷,视变体不同,该载荷可能包括远程代码执行或删除用户的主目录。

Wiz 补充说,该死人开关是根据来自命令与控制服务器的响应被选择性布防的:操作者可以返回一个值,指定要布防哪条命令,以及该开关应监视哪个令牌是否被撤销。Wiz 还指出,监控程序会查找来自用户端点的有效响应,因此任何在用户端点处有效的令牌类型都可以充当触发器。

实际后果由 BleepingComputer 记录,并引用了 Aikido 的指导:安装了受影响版本的开发者工作站或 CI/CD 运行器应被视为已遭入侵,即使该软件包随后已被移除,因为第二阶段执行可能已泄露令牌并破坏构建完整性。Microsoft 的指导从构建侧得出了相同结论,警告称,在启用生命周期脚本的情况下安装了受影响软件包的组织,应将该工作站或构建运行器视为可能已遭入侵,并从可信来源重建受影响的系统及下游产物。

An HTML card titled 'Established, assessed, and not shown', subtitled 'The same five analyses, sorted by how strongly each claim is supported — not by how confidently it is written'. Three columns. ESTABLISHED lists: the keyv maintainer's GitHub account was compromised, files were pushed to main and a release was published on 4 August 2026; at least keyv 6.0.0 shipped through the victim's own CI with valid provenance and SLSA Build Level 3; a preinstall hook ran setup.mjs, which downloaded Bun v1.3.13 to execute an obfuscated payload; the collector scanned 300+ credential patterns including Anthropic, Claude, Codex, Cursor, OpenAI and Gemini; hooks in .claude/settings.json and .vscode/tasks.json run on session start and folder open; a GitHub App token extended the hooks to up to 50 branches per accessible repository; more than 400 unique packages were compromised within days; CSA Singapore published advisory AD-2026-009 on 6 August 2026. ASSESSED lists: attribution to the Mini Shai-Hulud family and a TeamPCP lineage; that the account takeover was the initial access route; that provenance must not be read as proof of safety, since it validates the pipeline and not the account; that IDE configuration files should be treated as executable code. NOT SHOWN lists: how the maintainer account was taken over, reported as unknown by Zscaler; any single final total, since the counts use packages, versions and downloads interchangeably; any confirmed reuse of a stolen AI-tooling credential against a provider account; who the operator is beyond vendor attribution; any remediation outcome, account recovery or enforcement action. A footer cites Elastic Security Labs, Microsoft Threat Intelligence, Wiz Research, Orca Security and CSA Singapore AD-2026-009.

哪些是已确立的,哪些是已评估的,以及哪些尚无人展示

原始记录和五项独立分析在机制上相互印证,而机械性论断是该档案中最有力的部分。

• keyv 维护者的 GitHub 账号遭到入侵,在发布版本之前,恶意文件被直接推送到了 main 分支,此事发生于 2026 年 8 月 4 日——Wiz、Orca Security、BleepingComputer 和 CSA Singapore 均对此作出了一致报道。

• 至少 keyv 6.0.0 通过受害者自身的 CI 流水线进入了 npm,并带有有效的来源证明,Zscaler 还明确指出其具备 SLSA Build Level 3 证明。正是这一说法让该事件值得关注,而且它得到了三个并未共同撰写彼此工作成果的组织的佐证。

• 一个 preinstall 钩子执行了 setup.mjs,该脚本下载了 Bun v1.3.13,并运行了一段经过混淆的载荷,扫描了 300 多种凭据模式,其中包括 AI 编程工具的凭据——Elastic 和 Wiz 对运行时版本和针对 AI 的凭据列表这两点均持相同结论。

• 写入 .claude/settings.json 和 .vscode/tasks.json 的钩子会在会话启动时和打开文件夹时执行,而 GitHub App 令牌将此扩展到每个可访问仓库中最多 50 个分支——这是 Elastic 的发现,也是其称开发者仅因打开一个仓库就可能被感染的说法的依据。

• 在几天内,超过 400 个不同的软件包遭到入侵;2026 年 8 月 6 日,国家监管机构 CSA Singapore 发布了公告 AD-2026-009,列出了受影响的版本和入侵指标。

来源将其视为评估而非事实的内容,应加以标注。Wiz 将该载荷描述为“Mini”Shai-Hulud 恶意软件家族的后代,基于 TeamPCP 发布的公开 Shai-Hulud-Open-Source 代码库构建,但有几处关键改动;Orca Security 将此次攻击归因于 TeamPCP;Zscaler 将 ChainDrop 与 TeamPCP 联系起来,并将其置于一条可追溯至 2025 年 9 月的谱系中。这是供应商之间的归因共识,而不是所引用的原始文件就某个具名个人或组织所证明的内容。

有三件事没有任何被引用的来源能够证实,而本文也没有补充。第一,如何接管维护者账户:Zscaler 明确表示,在其分析之时,确切机制尚不清楚。第二,一个单一的最终总数:400、868 和 1,300 这几个数字在不同时间点分别统计的是软件包、软件包与版本组合以及版本,而且没有任何来源声称该活动已经结束。第三,也是本记录中与 AI 特定主张最相关的一点,没有任何被引用的来源报告过已确认的实例:被盗的 Anthropic、Codex、Cursor、Gemini 或 OpenAI 凭据被重放用于某个提供商账户。有记录的是意图与能力——一份明确的目标清单,以及一个为达成该目标而构建的收集器——而非经证实的对某家 AI 提供商系统的下游入侵。

之后发生了什么变化——以及响应者必须做什么

记录中最具体的补救措施是进行平台变更。Elastic 建议升级到 npm 12 或更高版本,该版本默认阻止预安装钩子;Microsoft 的指南也独立建议使用 npm CLI v12 和 min-release-age功能,该功能会将新版本推迟足够长的时间,使社区能在新版本进入构建之前发现其已被入侵。

除此之外,各来源发布的应对步骤存在大量重叠。

• Elastic:在所有受影响机器上撤销全部 GitHub 令牌,包括会话令牌;撤销并重新生成 npm 令牌,尤其是具有写入权限和绕过双因素认证的自动化令牌;在仓库中搜索带有 chore: update config from claude@users.noreply.github.com 提交信息的未经授权提交;轮换云、Kubernetes、Vault、AI 工具及 CI/CD 密钥;在 npm 账户上启用双因素认证。

• Microsoft:在受影响的终端和构建主机上清除 npm 和 yarn 缓存,固定已知良好的版本,审查锁文件和制品中是否包含被入侵的版本(包括传递引用),重建共享基础镜像和黄金构建运行器,并审查令牌作用域、工作流审批和发布溯源,因为该事件与通过 OIDC 发布滥用 CI/CD 管道的情况相符。

• CSA Singapore:从开发、构建和 CI/CD 环境中移除受影响版本,将受影响系统视为已遭入侵并重建,轮换凭据,审查云环境和源代码环境是否存在未经授权的访问,监控已发布的指标,并加强允许列表、完整性验证和来源控制。

• Zscaler:将 .claude/、.cursor/、.vscode/ 和 .gemini/ 视为可执行代码,并且不再将 SLSA 或 Sigstore 来源证明视为安全性的证明——转而将其与针对发布行为的异常检测叠加使用,例如非工作时间发布、批量版本发布以及首次发布者。

记录中不包含补救结果。所引用的来源均未报告恶意版本已被完全移除、账户恢复、逮捕或监管执法行动;CSA 的公告是面向防御者的通知,而非针对某一方的认定。

这起事件改变的是一个分类问题。开发者工具的配置文件就是一条执行路径,而编辑器打开一个文件夹就是一个执行事件。来源证明所陈述的是某个软件包由哪条流水线生产——而不是该流水线运行时谁持有密钥,而这正是首个 keyv 发布版本所落入的缺口。