KernelRanch
返回文章列表

依赖混淆的新变种:npm 包从明文 HTTP 拉取同名包

2026-11-10 #npm#dependency-confusion#security#supply-chain

这起事件记录在漏洞库编号 MAL-2026-18183 下,规模不大,但把依赖混淆(dependency confusion)的一个变种演示得非常清楚。

1. 攻击链

环节具体做法
宿主包发布在 @conduitops 作用域下
依赖指向一个裸 IP 的明文 HTTP registry:139.196.94.195:8080,属阿里云地址段
被拉取的包另一个作用域 @conduit 下的同名包
声明的发布方package.json 里写的是 *.conduit.internal 下的仓库、主页与问题追踪
结果安装时直接下载并执行该包的 tarball,含生命周期脚本

2. 三个同时失效的防线

TLS。registry 是明文 HTTP,中间人可以直接改写响应。

完整性校验。从这种地址拉取的包没有可对照的完整性信息,npm 不会拒绝。

作用域隔离。宿主包在 @conduitops,被拉取的包在 @conduit,两个作用域不一致,但依赖解析并不因此报错。

漏洞库给出的结论很直白:凡是装过或运行过这个包的机器,都应视为完全失陷。

3. 为什么这种变种更阴

传统的依赖混淆,是利用公共 registry 与私有 registry 的同名包抢占。这一种更隐蔽:它不需要抢占官方包名,只需要让宿主包把某个依赖地址改成一个自己控制的 endpoint。

攻击者甚至不需要发布到 npm 公共仓库的正规位置——一个裸 IP 上的 HTTP 服务就够了。成本极低。

4. 排查与处置

排查:在 package-lock.json 或 node_modules/.package-lock.json 里搜 http:// 开头的 resolved 地址,以及非 registry.npmjs.org 的域名或 IP。

处置:卸载该包、清理 lock 文件、轮换该环境能读到的所有凭据,然后检查安装时的网络连接记录(生命周期脚本会在这个阶段发起外连)。

长期防线有三条,成本都不高:在 npm 配置里把 registry 固定为 HTTPS 的私有代理;用 npm config set strict-ssl true 之外,再加 --ignore-scripts 的 CI 默认值;对 lock 文件里出现的非标准解析地址做正则拦截。

小结

依赖混淆的形态在变化:从"抢名字"变成"改地址"。防御的核心没变——安装依赖等于执行陌生代码,而"地址"也是攻击面的一部分。

一家公开漏洞库把这个包标记为"装过即失陷",理由是它拿到了安装时执行任意代码的能力。这个判断标准值得记住:在 npm 生态里,能跑 postinstall 就等于能跑任何东西。

数据来源与检索时间

检索时间 2026-11-10。

来源URL对应数据
Vulnerability-Lookup(CIRCL)MAL-2026-18183https://vulnerability.circl.lu/vuln/mal-2026-18183宿主包作用域 @conduitops、被拉取包作用域 @conduit、registry 为 139.196.94.195:8080 明文 HTTP(阿里云段)、*.conduit.internal 声明、无 TLS 无完整性校验、生命周期脚本执行、"视为完全失陷"的结论

核验说明

  • 字段与判断均来自该漏洞条目;IP 段归属(阿里云)也是条目原文的表述。
  • 未做:没有下载该包做动态分析,也没有复现安装过程;文中"常规防御建议"部分为通用实践,不是针对该样本的验证结果。