在 Red Hat Cloud Services 中检测到恶意 npm 包

事件范围

  • 恶意 npm 包被推送到了 Red Hat Cloud Services 的 JavaScript 客户端仓库,似乎是通过被攻陷的 CI/CD 管道(GitHub Actions + OIDC)完成的,而不是通过被盗的静态凭据。
  • 受影响的包是编译进某些 Red Hat 容器镜像的前端库;影响看起来主要落在这些镜像的使用者身上,而不是直接的 npm 用户。
  • 多项分析(在线程中有链接)列出了共享的管道,并将此归类为更广泛的“mini‑Shai-Hulud”/TrapDoor 风格 npm 蠕虫的一部分。

这是 npm 的问题,还是整个生态系统的问题?

  • 许多人认为,所有现代语言的包管理器(npm、PyPI、crates.io、Composer、NuGet、RubyGems 等)都共享同样的核心风险:任何人都可以发布,代码以较大的权限运行,而且维护者往往是个人。
  • 另一些人认为 npm 更糟,原因包括:
    • 生命周期/postinstall 脚本在安装时默认运行任意代码。
    • 巨大、深度嵌套的依赖图,以及大量微小包的文化。
    • “始终更新到最新版本”的快速演进规范。
  • 反方观点:生命周期钩子和类似特性在许多系统中都存在(dpkg/rpm、RubyGems、Pip、NuGet),因此有些人认为把责任只归咎于 npm 是不公平或带有偏见的。

提出的缓解措施

  • 依赖冷却期(1–7 天),避免安装新发布的版本,依赖扫描器和维护者在这段时间内发现恶意代码。pnpm、Yarn 4、npm 11、pip、uv,以及第三方工具都支持这一做法。
    • 支持者:成本低,在近期那些在数小时/数天内被发现的攻击中很有效。
    • 怀疑者:如果所有人都延迟,攻击者可以加入定时炸弹;同时仍需要处理紧急 CVE。
  • 加固 CI/CD
    • 将“构建/测试”和“签名/发布”作业分离,这样蠕虫就不能自动重新发布。
    • 使用可信发布者、MFA、分阶段发布;但如果 CI 本身被攻陷,这些措施也帮不上忙。
  • 缩小爆炸半径
    • 在容器、沙箱或低权限环境中运行安装/测试。
    • 避免使用同时持有敏感密钥或钱包的开发机器。
  • 治理与打包模型
    • 有人呼吁借鉴 Linux 发行版:受审查的维护者、多层审核、较慢的渠道(testing/unstable)。
    • 也有人建议 vendoring 依赖、固定精确版本、避免不必要的库,并优先选择依赖图更扁平、更小的生态系统。

文化批评

  • 多条评论把责任归咎于 JavaScript/Web 文化:小包泛滥、快速变化、深层传递依赖,以及对自动更新的高度依赖。
  • 另一些人强调,用户在出问题之前更看重便利而非安全;安全被视为一种隐形需求,往往在后期才被补上。