【安全评论】npm又中招了:”我们无法预防”——唯一经常发生此事的包管理器

admin 2026-05-19 06:00:37 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 2026年5月14日npm仓库发生node-ipc恶意包供应链攻击事件,三个恶意版本通过混淆代码窃取云凭证、SSH密钥等敏感数据。文章分析npm结构性缺陷(默认执行脚本、维护者不活跃、无审核机制)导致此类事件频发,并提供立即排查步骤、检测规则及构建时、运行时、运营时三层防御策略,强调需从根本上解决npm生态安全问题。 综合评分: 88 文章分类: 供应链安全,漏洞分析,恶意软件,安全运营,解决方案


cover_image

【安全评论】npm 又中招了:”我们无法预防”——唯一经常发生此事的包管理器

原创

Blake Chen Blake Chen

黑白之道

2026年5月18日 08:31 江西

在小说阅读器读本章

去阅读

导语:2026年5月14日,npm 仓库中三个恶意版本的 node-ipc 包被同时发布,意图窃取全球开发者的云凭证、SSH 密钥和 AI 工具配置。这不是 npm 第一次发生这种事,当然也不会是最后一次。每隔几个月,整个 JavaScript 生态就会经历一次这样的”自然灾难”——而官方每次的回应,都是那句令人熟悉的”我们真的无法预防”。


一、事件回顾:一颗定时炸弹如何被引爆

1.1 事件经过

2026年5月14日,npm 账户 atiertant(关联邮箱 [email protected])在同一时刻发布了三个恶意版本的 node-ipc 包:

  • [email protected](虚构版本号,9.x 分支此前从未有 CommonJS 构建)
  • [email protected](同上)
  • [email protected](针对特定目标的高精度攻击版本)

该包每周下载量高达 822,000 次,历史累计下载超过 10,000,000 次。一旦开发者在项目中使用 npm install node-ipc(未锁定版本),恶意代码便会通过 require('node-ipc') 自动加载,无需任何触发条件。

1.2 恶意代码行为分析

恶意 payload 被注入在 node-ipc.cjs 文件末尾(第 1271 行),是一个 80,079 字节的混淆 IIFE(立即执行函数)。payload 执行流程如下:

阶段一:配置解码

// 自定义 Base-16 编码的 C2 配置
// 解码后得到:
r: 'sh.azurestaticprovider.net:443',  // C2 地址(伪装成 Azure)
k: 'qZ8pL3vNxR9wKmTyHbVcFgDsJaEoUi',  // HMAC 认证密钥
z: 'bt.node.js',                       // 请求标识符

阶段二:定向指纹(仅 12.0.1)

12.0.1 版本内置了 SHA-256 定向指纹校验,会比对当前模块路径的哈希值。只有匹配预设目标的系统才会执行完整 payload,非目标系统则静默退出。这意味着攻击者已经锁定了特定的开发环境或项目。

阶段三:凭证窃取

payload 会尝试窃取超过 90 类敏感数据,包括:

| 类别 | 目标路径 | | — | — | | 云凭证 | ~/.aws/credentials~/.azure/accessTokens.json~/.config/gcloud/credentials.db | | SSH 密钥 | ~/.ssh/id_rsa~/.ssh/id_ed25519/etc/ssh/ssh_host_*_key | | AI 工具配置 | ~/.claude.json~/.claude/mcp.json.kiro/settings/mcp.json | | 基础设施即代码 | ~/.terraform.d/credentials.tfrc.json**/terraform.tfvars | | CI/CD 工作流 | **/.github/workflows/*.yml**/.gitlab-ci.yml | | Shell 历史 | ~/.bash_history~/.zsh_history |

阶段四:双通道数据外泄

  1. HTTPS 外泄:将窃取数据压缩为 gzip,通过 HTTPS POST 上传至 sh.azurestaticprovider.net
  2. DNS TXT 外泄:绕过企业 DNS 监控,直接将数据编码为 DNS 查询发送至 C2 服务器 IP

二、历史重演:npm 为何总是”无法预防”

2.1 这不是第一次

node-ipc 并非首次被滥用。2022年3月,该包的 10.1.1 和 10.1.2 版本曾被用于部署名为 peacenotwar 的恶意负载——在特定地区用户的家目录下创建 USE_PEACE_NOT_WAR 文件夹,并在特定触发条件下删除系统文件。

两次攻击,背后是不同的威胁行为者,却利用了同一个 npm 包生态位

2.2 npm 的结构性缺陷

讽刺文章的核心论点在于:npm 是唯一一个定期发生此类事件的包管理器。为什么?

问题一:默认执行任意代码

npm 默认会在 npm install 时执行包中的 preinstallinstallpostinstall 脚本。这意味着当你执行 npm install foo 时,你实际上是在告诉系统”请下载这个未知来源的代码压缩包,然后以当前用户权限执行其中的任意脚本”。

这在设计上就是一次供应链攻击的完美入口。

问题二:维护者账户长期不活跃

node-ipc 的原作者 Brandon Nozalski Miller(GitHub 用户名 RIAEvangelist)自 2024年8月12日 发布 12.0.0 后便停止维护。21个月后,攻击者获得了维护者权限,发布了三个恶意版本。在 npm 的生态中,高下载量但无人维护的”孤包”是典型的狩猎场。

问题三:版本发布无审核期

当攻击者在同一天、同一时刻发布三个版本覆盖不同 semver 范围时,没有任何机制可以阻止这一切发生——直到安全研究员发现并手动举报。

对比其他生态

讽刺文章指出,在 Go、Rust 等生态中,由于语言自带强标准库和严格的构建工具链,开发者对第三方代码的依赖深度远不及 npm,因此类似事件的频率和影响也低得多。


三、蓝队视角:我们能做什么

3.1 立即排查

如果你的项目使用了 node-ipc,请执行以下命令:

# 检查直接依赖版本
npm ls node-ipc

# 搜索 lockfile 中的受影响版本
grep -E '"node-ipc".*"(9\.1\.6|9\.2\.3|12\.0\.1)"' package-lock.json

# 检查 CI/CD 和开发者机器上的安装历史
npm list node-ipc --all

如果发现存在受影响版本,请立即假设凭证已失陷,执行以下操作:

  1. 轮换所有在失陷系统上使用过的凭证(AWS密钥、SSH密钥、GitHub Token等)
  2. 检查 CI/CD 环境的网络外泄日志
  3. 检查 $TMPDIR/nt-* 目录是否存在(payload 临时文件)
  4. 检查环境变量中是否存在 __ntw=1(daemon 进程标记)

3.2 构建检测规则

SIEM 检测示例(Splunk SPL)

# 检测失陷版本安装
index=npm_logs event_type=install (version="9.1.6" OR version="9.2.3" OR version="12.0.1")
| stats count by host, user, version, timestamp

# 检测 C2 域名访问
index=network_logs dest_domain="sh.azurestaticprovider.net" OR dest_ip="37.16.75.69"
| stats count by src_ip, dest, timestamp

# 检测异常 DNS 外泄查询(直接到非标准DNS服务器)
index=dns_logs src_ip!=10.0.0.0/8 query="*.bt.node.js"
| stats count by src_ip, query, timestamp

3.3 长期防御策略

纵深防御三层面

层面一:构建时(Build-time)

  • 启用 npm config set ignore-scripts true,禁止自动执行 install 脚本
  • 使用 npm ci 而非 npm install,确保 lockfile 精确匹配
  • 部署私有 npm 镜像(如 Verdaccio),所有包经过安全审核后再进入内部生态
  • 使用 Socket.dev 或 Snyk 的包分析功能,在安装前评估包的安全风险

层面二:运行时(Runtime)

  • 限制 CI/CD 环境的外向网络流量,仅允许必要端点
  • 在开发者工作站上启用 EDR 监控 npm 安装行为
  • 使用容器化构建环境,确保每次构建在隔离环境中执行

层面三:运营时(Operations)

  • 建立 npm 包监控机制,追踪项目依赖的健康状态
  • 对高风险包(长期不更新、大量下载、作用域可疑)进行标记
  • 将供应链安全纳入漏洞响应流程,设立专门的应急响应通道

四、结语:我们还能说什么

每次 npm 供应链事件发生后,官方都会发表一份声明,表示遗憾,并强调”无法预防”。而社区则会在短暂愤怒后,继续 npm install,继续信任下一个 40 层深的依赖树。

作为蓝队,我们习惯了”假设已被攻破”的思维模式。但在 npm 这里,攻破从未停止——它就是日常。

讽刺文章的最后一句话说得很好:“直到明天早晨的下一场不可避免的灾难,我们必须保持韧性。”

韧性当然重要。但韧性不意味着每次都用临时补丁去修补一个根本不该存在的伤口。

或许,是时候认真讨论一下 npm 的结构性安全问题了。


版权声明:本文由华盟网原创发布,保留所有权利。配图由华盟网授权使用。


👇 点击阅读原文,访问我的网站



免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:黑白之道 Blake Chen Blake Chen《【安全评论】npm 又中招了:”我们无法预防”——唯一经常发生此事的包管理器》

评论:0   参与:  0