
























事情的起点只是一次普通的 CI 打包失败,根因排查到最后却指向一个本该已经被 npm 官方下架的恶意版本:@antv/[email protected]。更没想到的是,因为我在本地为了复现问题而使用公司私服重新安装依赖,直接触发了恶意代码并被安全软件告警,最终导致个人开发账号被临时封禁。
本文记录完整时间线、攻击机制、凭据风险以及处置与治理建议,供遇到类似问题的团队与个人参考。
说明:本文已将公司内部私服域名、账号名称、项目名、内网镜像地址、人员等信息做脱敏处理;图片路径保持原样,相关公开 IOC 与外部参考链接也保持原样。
公司私有 npm 仓库(下文统一称“公司私服”)上缓存的 npm 包 @antv/[email protected] 包含恶意代码。开发者如果在本地执行如下命令,并安装到了该版本,就会触发恶意逻辑:
pnpm install --no-frozen-lockfile --registry https://***公司私服域名***/nexus/repository/npm/
本次恶意代码属于 AntV 相关 npm 包被投毒事件的一部分。它会在安装阶段执行 payload,扫描并收集本机和 CI 环境中的敏感凭据,并向 m-kosche.com、t.m-kosche.com 等域名发起请求。根据公开分析,外传数据会经过 gzip、AES-256-GCM 和 RSA-OAEP 混合加密,网络侧即使捕获请求,也很难直接还原明文内容。
最终影响是:我在本地为了复现打包机问题,使用公司私服重新安装依赖,触发了 @antv/[email protected] 中的恶意逻辑。安全软件随后检测到供应链攻击行为并触发告警,我的内部开发账号被临时封禁。
本次事件与 2026-05-19 AntV npm 包投毒事件一致,公开参考资料如下:
AntV 官方在 GitHub 组织首页发布了如下公告:
2026-05-19 早上 10 点
@antv相关的 NPM 包遭受外部蠕虫攻击投毒。我们已经在 1 小时内 deprecate 所有受感染的包,在 4 小时内联系上 NPM 官方删除所有受感染的包,目前已经完全解决相关漏洞和安全风险,请受波及的用户及时清除本地缓存重新安装依赖。
这说明 npm 官方源上的受感染版本理论上已经在 2026-05-19 当天被处理。但公司私服在 2026-05-26 仍同步并缓存了 @antv/[email protected],导致 2026-05-28 内部安装依赖时仍可命中恶意版本。
上午 11 点多,同事反馈某前端项目打包失败。查看 Jenkins 日志后,发现报错如下:
ERROR Command failed with exit code 128: git fetch --depth 1 origin 1916faa365f2788b6e193514872d51a242876569
ssh: connect to host github.com port 22: Connection refused
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
pnpm: Command failed with exit code 128: git fetch --depth 1 origin 1916faa365f2788b6e193514872d51a242876569
ssh: connect to host github.com port 22: Connection refused
fatal: Could not read from remote repository.
该 Jenkins 环境没有外网访问权限,正常情况下不应该访问 github.com。结合以往经验,初步判断是某个依赖包中引入了类似如下形式的 GitHub 依赖:
"xxx": "git+ssh://[email protected]/xxx/xxx.git#1916faa..."
因此当时的处理思路是:先识别具体依赖,再通过升级或回退版本,找到不依赖 GitHub 的可用版本。
为了找出具体依赖,我分两条路径排查:
pnpm install --reporter,输出详细安装日志,分析 github.com 请求来自哪个依赖。pnpm install,通过网络嗅探工具监听 github.com 请求,辅助定位目标依赖包。打包机上通过 Docker 执行的命令(示例)如下:
docker run --rm -it --user root -v $(pwd):/app -v /data/pnpm-store:/data/pnpm-store -w /app ***/registry/library/gplane/pnpm:10.28-node22 bash -c 'pnpm config set store-dir /data/pnpm-store && git config --global url."https://github.com/".insteadOf "[email protected]:" && git config --global url."https://github.com/".insteadOf "ssh://[email protected]/" && git config --global url."https://github.com/".insteadOf "git+ssh://[email protected]/" && PNPM_DEBUG_LEVEL=debug pnpm install --no-frozen-lockfile --registry https://***公司私服域名***/nexus/repository/npm/ --reporter ndjson 2>&1 | tee /app/pnpm-install-debug.log'
等待打包机输出报告期间,我先在本地用官方 npm 源执行 pnpm install。本地没有出现 github.com 请求,因此基本排除了项目自身依赖变更导致的问题,进一步怀疑是公司私服上的包内容异常。
随后我为了模拟打包机环境,在本地执行了:
pnpm install --no-frozen-lockfile --registry https://***公司私服域名***/nexus/repository/npm/
执行后,本地也复现了 github.com 请求。也正是在这个过程中,本机安装到了公司私服中的恶意包,触发了供应链攻击。
下午分析打包机上的 pnpm install 报告后,定位到问题依赖链如下:
@antv/[email protected]
↓
依赖 @antv/setup
↓
@antv/setup 不是普通 npm 包
↓
而是引用 GitHub commit 1916faa365f2788b6e193514872d51a242876569
当时只从构建失败角度处理,认为是 @antv/[email protected] 引入了无法访问的 GitHub 依赖,因此通过固定旧版本解决打包问题:
{
"pnpm": {
"overrides": {
"@antv/expr": "1.0.2",
"@antv/vendor": "1.0.11"
}
}
}
结合后续公开分析,这里的 @antv/setup 并不是普通依赖错误,而是 Mini Shai-Hulud 攻击中的备用执行路径。恶意包通过 optionalDependencies 引入 github:antvis/G2#1916faa365f2788b6e193514872d51a242876569,GitHub commit 中包含带 prepare 生命周期脚本的 payload。即使主路径 preinstall 被限制,仍可能通过 GitHub 依赖触发安装期执行。
主管收到安全平台告警邮件,邮件显示检测到我的电脑遭遇供应链攻击。出于安全策略,我的内部开发账号被临时封禁,需要重装系统后才能解封。
邮件中的 IOC 信息提到了 m-kosche.com。在此之前,我没有主动访问过该域名,因此开始反查本机访问来源。
第一时间在本机 /etc/hosts 中添加如下配置,将相关域名指向本地,阻断继续访问:
127.0.0.1 m-kosche.com
127.0.0.1 t.m-kosche.com
需要注意的是,结合 Socket 和 SafeDep 的分析,t.m-kosche.com 只是主要外传通道之一。payload 还可能通过 GitHub API 创建仓库并把数据提交到 results/ 目录作为 fallback 外传通道。因此,仅阻断域名并不能证明风险已经完全消除。
确认 IOC 域名后,排查分为三步:
11:34,与本地使用公司私服执行 pnpm install 的时间高度重合。m-kosche.com 和 antv 相关信息,找到 Cremit、SafeDep、Socket 等公开分析文章,确认这是 AntV 相关 npm 包投毒事件。公开资料中提到,本次攻击发生于 2026-05-19,AntV 官方已经在当天对 npm 官方源上的受感染包执行 deprecate 和删除处理。理论上,2026-05-28 从官方 npm 源已经不应该安装到恶意包。
结合我本地只有在切换到公司私服后才复现问题,基本可以确认:公司私服缓存了已经从官方源移除的受感染版本。
随后下载并比对 @antv/[email protected],确认其内容与公开文章描述的攻击特征一致,最终锁定本次攻击来源为公司私服中的 @antv/[email protected]。

本次事件中最直接的触发路径是:
pnpm install
↓
安装 @antv/[email protected]
↓
执行恶意安装脚本或 GitHub optionalDependency 中的 prepare 脚本
↓
扫描本机和 CI 环境中的凭据
↓
通过 m-kosche.com / GitHub fallback 通道外传
公开分析显示,受感染包通常会包含两类执行路径:
preinstall 生命周期脚本:通过 bun run index.js 执行根目录下混淆后的 index.js。optionalDependencies GitHub 依赖:通过 @antv/setup 指向 antvis/G2 中的 orphan commit,并在该依赖的 prepare 阶段执行 payload。本次 Jenkins 打包失败暴露出来的 1916faa365f2788b6e193514872d51a242876569,正是公开 IOC 中出现频率最高的 imposter commit。
根据 Cremit、SafeDep 和 Socket 的分析,该 payload 目标不是单一密钥,而是广泛扫描开发者电脑和 CI/CD 环境中的敏感信息,主要包括:
gh CLI 配置。.npmrc、npm publish token。pass、gopass 等本地密码管理器相关数据。因此,只要在受影响机器上执行过恶意包安装,就应该按照“本机可访问凭据均存在泄漏风险”处理,而不是只轮换某一个被明确捕获的 token。
公开资料还提到,该 payload 可能写入 AI 编程工具和 IDE 配置,从而在后续打开项目或启动 AI 会话时再次执行。需要重点检查以下路径:
.claude/settings.json
.claude/setup.mjs
.claude/index.js
.vscode/tasks.json
.vscode/setup.mjs
~/.claude/package/index.js
~/.codex/package/index.js
其中 .claude/settings.json 可能包含 SessionStart hook,.vscode/tasks.json 可能包含 runOn: folderOpen 任务。这意味着攻击可能不只发生在执行 pnpm install 的当下,还可能通过仓库文件或本地配置形成后续持久化。
结合内部时间点和公开事件时间线,影响链路如下:
@antv/[email protected]。@antv/[email protected]。由于该包引入 github:antvis/G2#1916faa365f2788b6e193514872d51a242876569,而打包机没有 GitHub 访问权限,导致打包失败,并出现 ssh: connect to host github.com port 22: Connection refused。pnpm install --no-frozen-lockfile --registry https://***公司私服域名***/nexus/repository/npm/,从而触发恶意代码。打包机每次打包都通过 Docker 沙盒运行,并且没有外网访问权限。从现有现象看,恶意包在打包机上主要表现为尝试访问 GitHub 后失败,没有成功完成外传请求,因此打包机风险相对较低。
但仍建议清理打包缓存和 pnpm store,避免后续构建继续命中受感染包。
我的本地开发机已经执行过公司私服安装,并触发安全告警。因此应按高风险处理:
如果其他人在 2026-05-26 11:15 到 2026-05-28 14:36 之间执行过如下命令,也需要按受影响处理:
pnpm install --no-frozen-lockfile --registry https://***公司私服域名***/nexus/repository/npm/
尤其需要关注是否安装到 @antv/[email protected],以及 lockfile 中是否出现以下 IOC:
@antv/[email protected]
@antv/setup
github:antvis/G2#1916faa365f2788b6e193514872d51a242876569
t.m-kosche.com
m-kosche.com
@antv/[email protected] 及相关受感染版本。*.m-kosche.com。m-kosche.com、t.m-kosche.com 的访问记录。--no-frozen-lockfile。preinstall、postinstall、prepare 生命周期脚本建立审查机制。optionalDependencies 中的 github:、git+ssh:、git+https: 依赖建立告警或阻断策略。.claude/setup.mjs、.vscode/setup.mjs、~/.claude/package/index.js、~/.codex/package/index.js 等可疑文件。.claude/settings.json 中是否存在异常 SessionStart hook。.vscode/tasks.json 中是否存在 runOn: folderOpen 且执行 setup.mjs 的任务。<word>-<word>-<digits> 命名风格),以及 results/results-*.json 文件。这次事件最开始表现为一次普通的 Jenkins 打包失败,但根因不是依赖版本不兼容,而是公司私服缓存了已经从 npm 官方源移除的恶意包。
本次事件暴露出几个问题:
pnpm install --no-frozen-lockfile 会扩大供应链风险,尤其是在私服缓存存在污染时。后续需要把“依赖安装失败访问 GitHub”这类异常从普通构建问题提升为供应链风险信号处理,尤其是当异常 commit SHA 与公开 IOC 匹配时,应优先隔离环境并暂停继续安装,而不是直接在本地复现。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。