2026 年 9 月 21 日,全球下载量巨大的 TypeScript 类型验证库 Zod 代码仓库出现异动。一个伪装成性能优化的恶意提交被强行推入主分支,试图将版本号跳升至 4.6.6,并在安装流程中引入暗中调用以太坊智能合约的二阶段加载器。

然而社交网络上流传的感染恐慌并未成为现实。虽然攻击者拿到了代码推送权限,但受损代码从未进入 npm 官方注册表。现代软件供应链防御中部署的发布环境门禁与凭证隔离机制,在关键时刻切断了自动化恶意发布的链路,将一场可能席卷数百万项目的供应链危机拦在生产大门之外。

潜入主分支的木马:伪装成补丁的以太坊寻址器

根据记录,恶意提交 d821685 发生于 2026 年 9 月 21 日 11:56:52 UTC。攻击者打着修复缺陷与提升性能的旗号,对核心包与子模块进行了多处改动。其核心载荷是一个名为 meta.test.mjs 的隐蔽脚本,配合修改了相关的包配置文件。

这段代码采用了安全界称为 EtherHiding 的链上隐蔽信道技术。它没有在脚本中硬编码容易被静态扫描识别的恶意控制端域名,而是直接利用公共 RPC 节点,向以太坊合约发起调用。

以太坊合约 C2 寻址与投毒链条分解 1. 链上寻址 调用公共 RPC 节点 查询目标智能合约 解包获取 C2 域名 2. 动态载荷拉取 向动态域名请求 loader 解析 Base64 编码载荷 落盘写入操作系统临时区 3. 执行与销毁 动态 import 内存执行 触发全局引导信号 强制擦除临时落地文件 核心特征:利用区块链不可篡改性充当死信箱,躲避常规域名阻断

具体而言,恶意载荷轮询 Cloudflare 与公共 RPC 节点,向合约地址发起调用,解析返回值以还原真实的控制服务器域名。在获取到后续载荷后,代码在临时目录解密并落盘,执行完内存载入后迅速将自身物理删除。这种把区块链当成不可篡改死信箱的手段,让传统的网络层封锁和静态特征库很难提前防御。

阻断与失误:双重关隘如何让投毒失效

尽管潜入手段精密,这次针对核心依赖的伏击最终却全面落空。维护者 Colin McDonnell 随后证实,自己的代码推送权限确实疑似外泄,攻击者借此直接越过了分支保护。但恶意代码在抵达开发者电脑前,遇到了两道不可逾越的屏障。

第一道屏障来自工程机制。黑客试图修改 GitHub Actions 的工作流配置,让提交事件自动触发发包。但 Zod 引入了 npm Trusted Publishing 机制与受保护环境。在自动化流水线中,发布任务受到环境审批策略的严格约束,哪怕流水线被触发,缺少合法维护者的人工批准,OIDC 临时令牌就不会下发。同批次攻击中,恶意包 @nubjs/nub@0.9.4 虽然一度到达发布流水线,同样在公开可用前被拦截。

挡住这场投毒的不是代码审查,而是流水线上不讲情面的发布审批门禁。
Zod 供应链投毒攻防对照 攻击面突破 推送凭证:攻破主分支写入权限 版本劫持:强推 4.6.6 等虚假版本 流程篡改:强行改写 Actions 触发源 意图:绕过常规代码审查直通 npm 工程与机制拦截 OIDC 门禁:缺少人工环境审批无法签名 语法错误:preinstall 脱离 scripts 字段 清理响应:PR #6620 快速回滚恶意变更 结果:合法发布物未受任何污染

第二道屏障则源于攻击者自身的低级失误。代码审查显示,黑客将触发脚本运行的 preinstall 钩子错误地写在了配置文件的根层级,而不是标准的 scripts 对象内。按照包管理器的既有解析规则,即便这批软件包侥幸打包发布,用户在执行安装时也根本不会触发这段恶意载荷。

维护者随即通过 PR #6620 展开清洗,回滚了包括后续 4.6.7 与 4.6.8 在内的版本跳变提交。最终在 npm 注册表上发布的合法 zod@4.6.6,完全基于修复后的干净代码构建。

  • 结论.只要下游工程使用官方 npm 镜像拉取依赖,生产环境便无需恐慌;真正的风险仅限于在事发数小时内直接锁定特定 Git 提交构建的极端场景。

现代流水线的防线启示

这场有惊无险的未遂事件,给近年来风声鹤唳的开源供应链安全提供了一个具象的解剖样本。攻击者的策略在快速演进:传统的投毒往往依赖高仿包名或窃取长期有效的发包密钥,而这起事件展现了更复杂的链条,黑客不仅尝试篡改持续集成配置,还动用了抗封锁的智能合约基础设施。

但它同样证明了防御体系重构的价值。以往开源项目极度依赖单一维度的开发者个人安全意识,私钥一旦外泄即全盘皆输。Zod 能够守住底线,本质上是因为现代发布流程将推送权限与发包权限做了强物理隔离。

  • 提醒.开源项目切断直连发包权限虽能阻断投毒,但能被未授权提交直推主分支,说明敏感分支保护与推送凭证的多因素管控仍需加固。

对广大依赖开源库的开发团队而言,警报虽已解除,但排查姿态不能松懈。依赖管理工具锁死在官方 npm 语义化版本中的项目处于安全状态,但对于内部工作流中包含直接拉取主分支最新代码的工程,收紧对特定 Git 提交哈希的依赖策略,已是刻不容缓的防御功课。