Zod 4.6.6 曝 npm 供应链投毒:恶意 preinstall 借以太坊合约取指令

2026 年 10 月 11 日至 12 日,npm 生态中广泛使用的 TypeScript 校验库 Zod 被曝出供应链投毒事件:维护者仓库的主分支上曾被推入一段恶意 preinstall 脚本,安装时经以太坊智能合约获取指令并执行第二级载荷。好消息是恶意版本最终没有进入 npm 正式分发包,npm 的发布时扫描在入口处拦下了唯一提交成功的包;但恶意提交在仓库历史里停留了数周,Zod 4.6.6 的 GitHub 发布页一度仍直接链向它。

事件概述

10 月 11 日,一名开发者在升级前审计 Zod 4.6.6,开出了 GitHub issue #6658:”Suspicious preinstall script in v4.6.6 commit history”。同一小时内,相同手法与误导性提交信息还出现在 standard-schema/standard-schema 与 nubjs/nub。

恶意提交向 zod 与 @zod/mini 的 package.json 注入了新文件 meta.test.mjs 与一条 "preinstall": "node meta.test.mjs" 钩子。三个被入侵仓库中,只有 @nubjs/nub@0.9.4 走到了 npm 发布流水线并被发布时扫描拦下;zod 与 standard-schema 的改动始终没有构建成可分发包。

技术细节

恶意脚本在安装阶段执行,过程大致分五步:调用多个公共以太坊 RPC 节点,对硬编码合约地址 0xe236330379d0c54aD5b2ef06aC714CEbdd4Ce523 发起 eth_call;把返回结果解码为域名列表;从这些域名的 /loader 端点拉取含 setupB64、payloadName、payloadB64 的 JSON;把载荷写入临时目录,再通过 data:text/javascript;base64 动态导入执行;最后清理临时文件。

这类设计的巧妙之处在于指令不在包内容里,而在链上合约中。合约无法像恶意域名那样被下架或封禁,攻击者可在不发布新版本的前提下随时更换投递地址,因此基于已知恶意域名或文件哈希的静态检测会失效。

影响评估

Zod 零运行时依赖、单维护者、约 2.9 亿次周下载、13.1 万个项目直接依赖,属于供应链最短也最”值得信任”的形态,仍差点投出加载器。真正的信任边界从来不是”谁写了这个库”,而是”谁掌握能推送到主分支的 git 凭证”——同类事故 2026 年已连续发生,5 月的 @tanstack/zod-adapter 与 8 月的 ChainDrop 蠕虫均属此列。

Zod 作者在当天即回滚了恶意提交(PR #6620),并把所有包的发布改为环境级分阶段发布、每次发布都要求 2FA。需提醒的是:回滚不等于清除,被回滚的提交仍可被 git checkout 或 git blame 触达。

修复建议

  • 检查 package.json 与 lockfile 是否出现 zod 或 @zod/mini 4.6.6,如有则回退到此前安全版本;
  • 排查 CI 与构建日志中是否有对 dsakldjklsaj33112[.]com 的请求,以及哈希 5ed518aaff…c9fd5a0b 的文件;
  • CI 中改用 npm ci 而非 npm install,锁定 lockfile,避免静默解析新版本;
  • 关闭不必要的安装期脚本(pnpm 默认关闭);
  • 轮换可能被安装期脚本读取的部署密钥与令牌,对发布令牌强制 2FA 并采用受信任发布;
  • 清理受污染提交时,需同步处理标签、发布说明与固定提交链接,避免”已回滚”被误读为”已清除”。

参考来源