npm 使失效绕过双因素认证的精细访问令牌——Mini Shai-Hulud 横扫注册表
npm 使所有绕过双因素认证的具有写权限的精细访问令牌失效。此举发生在一波新的 Mini Shai-Hulud 攻击入侵 323 个 npm 包之后。分阶段发布也已进入公开预览阶段。
npm 已使所有绕过双因素认证(2FA)的具有写权限的精细访问令牌失效。该平台范围的凭证重置于 5 月 19 日推出,并通过 npm 长期沉寂的 X 账户发布公告。
在 registry 发布该通知之前,一次攻击利用被劫持的维护者账户在 @antv 生态系统发布了数百个恶意包版本。
"为防止继 Mini Shai Hulud 模式之后的供应链攻击,我们使所有绕过 2FA 的具有写权限的 npm 精细访问令牌失效,"npm 在通知中写道,并告知维护者更新存储的令牌并重新运行使用这些令牌的自动化流程。registry 向用户推荐使用 OIDC 信任发布来减少对长期存在密钥的依赖。
该重置恰逢持续的 Mini Shai-Hulud 活动在过去三周内席卷 JavaScript 生态系统,并且紧随 GitHub 自身内部仓库被入侵之后——入侵可追溯到同一波攻击。
触发重置的攻击浪潮
5 月 18 日深夜,攻击者控制了 npm 维护者账户 atool,并在单次自动化爆发中推送了 639 个恶意版本,分布在 323 个独立包中。攻击浪潮落在 @antv 数据可视化生态系统,以及 echarts-for-react(约每周 110 万次下载)、timeago.js、size-sensor 和 canvas-nest.js 等包。
@antv 攻击浪潮之前是 5 月 11 日对 42 个 TanStack npm 包的入侵(共计 84 个恶意版本),其中包括每周下载量达 1200 万次的 @tanstack/react-router。TanStack 的事后分析将这次入侵追溯到一条链式漏洞:pull_request_target "Pwn Request" 滥用、GitHub Actions 缓存投毒,以及从运行器进程内存中直接提取 OIDC 令牌。整个过程不需要被盗的精细访问令牌。所有攻击都绕过了信任发布——而 npm 现在正力荐维护者采用的控制措施。
一周后,GitHub 披露攻击者已窃取了大约 3800 个内部仓库。首席信息安全官 Alexis Wales 最终确认入侵入口是 Nx Console,一个拥有 220 万次安装量的 Visual Studio Code 扩展。攻击者使用在 TanStack 入侵期间从 Nx 维护者处窃取的凭证发布了有毒的 v18.95.0,该版本在 Visual Studio Marketplace 上停留了 18 分钟才被移除。这个时间窗口足以让运行自动更新的开发者受到感染,并交付了最终让攻击者进入 GitHub 的凭证。
在整个 Mini Shai-Hulud 活动中,Socket 已追踪到 1055 个恶意版本,分布在 502 个独立包中,跨越 npm、PyPI 和 Composer。该活动被归因于 TeamPCP,已席卷 Bitwarden CLI、Checkmarx KICS/AST、Aqua Trivy、SAP CAP、Intercom、Mistral AI、UiPath,以及现在的 TanStack 和 @antv。
令牌重置的局限性
绕过 2FA 的选项是按设计存在的。npm 提供此选项是为了让 CI/CD 工作流可以无需交互式 2FA 提示即可发布,代价是将长期存在的令牌存储在密钥存储中,随时可能被任何落在运行器上的蠕虫窃取。Mini Shai-Hulud 正是为此而生,它扫描开发者机器和 CI 环境以寻找 npm 凭证,并利用窃取的令牌重新发布受害者维护的每个包的恶意版本。
通过燃尽平台上所有绕过 2FA 的令牌,npm 切断了蠕虫已经收集的凭证。维护者生成新的令牌。仍在野外活跃的蠕虫回到收集状态。重置争取了喘息空间,但没有关闭根本漏洞。
它也没有触及过去一个月最具破坏力的攻击模式。Bitwarden CLI 于 4 月 23 日随credential窃取有效载荷发货,攻击者直接入侵了项目的 publish-ci.yml 工作流,绕过了 Bitwarden 的信任发布控制。TanStack 的攻击者从 GitHub Actions 运行器内存中提取了 OIDC 令牌。两种攻击都无需长期存在的绕过 2FA 令牌即可成功。
信任发布存在的缺口被近期攻击利用
npm 推荐迁移到信任发布的依据是:从发布路径中移除静态令牌可以关闭攻击者不断穿行的门。但最近的入侵已经动摇了这一前提。
JavaScript 维护者、OpenJS 安全工作参与者 Wes Todd 在 12 月警告说,"新的 OIDC 信任发布者工作流在设计和实现上的缺口,会让维护者的发布设置暴露于新颖且越来越难以检测的漏洞中。"OpenJS 基金会没有在其指导中建议将信任发布用于关键项目,而是敦促团队根据自己的实际风险配置文件来匹配发布控制。
信任发布也无法用于发布新包,且在发布时不需要人工审批步骤。批量配置和扩展的 CI 提供商支持,这两项在 1 月被标记为缺口的特性,现已发布:批量信任发布配置于 2 月在 npm CLI v11.10.0 中达到 GA 状态,CircleCI 于 4 月作为支持的 OIDC 提供商加入了 GitHub Actions 和 GitLab CI/CD,填补了维护者自 9 月以来一直向 GitHub 施压解决的缺口。
在整个生态系统中的采用情况仍然参差不齐,最近的攻击浪潮表明攻击者会劫持该控制而不是试图破解它:TanStack 的攻击者通过项目的合法 OIDC 信任发布者绑定来认证其恶意发布,从工作流的 id-token 权限中 mint 发布令牌,并直接 POST 到 npm registry。
维护者们在 X 上对 npm 的令牌失效公告反应不一,夹杂着怀疑和疲惫。多条回复将令牌重置描述为一项流程变更,但没有解决底层的恶意软件问题。
分阶段发布进入公开预览
npm 对 Mini Shai-Hulud 的更有意义的响应与令牌重置同时到来,但获得的关注少得多。分阶段发布于 1 月首次宣布,5 月 20 日进入公开预览,当时 GitHub 将 npm stage 命令合并到 npm CLI v11.15.0 中,并更新了 registry 文档以描述该流程。
在新模型下,来自 CI 工作流的发布可以路由到一个暂存区域,而不是直接进入公共 registry。维护者通过 CLI 或 npmjs.com 执行 MFA 验证的审批步骤,然后版本才能被安装。蠕虫通过窃取的凭证推送恶意版本仍会在这里被暂停。
该功能通过一个新的 npm stage publish 命令和每个包的信任发布者配置上相应的"允许操作"字段提供,维护者在此选择自动化发布是使用 npm publish、npm stage publish,还是两者兼用。审批子命令(npm stage list、npm stage view、npm stage approve、npm stage reject)需要交互式 MFA,不能由 OIDC 令牌执行,从而将人工审查重新纳入流程。
分阶段发布是可选的,叠加在信任发布之上,默认情况下不会在现有信任发布者配置上启用。管理数十或数百个包的维护者必须为每个包单独配置它。该特性在高性能命名空间中的传播速度将决定它对下一波 Mini Shai-Hulud 提供多少实际保护。
安全研究员 Adnan Khan 在 X 上对该特性做出了最热情的倡导,告诉维护者 ["今天每个发布到 NPM 的人都应该开启这个功能。"] 他将其定位为对抗 Shai-Hulud 的直接对策:通过 OIDC 从 CI 发布,在包上线前审批,蠕虫的重新发布循环就会死在分阶段审批的门禁。
npm 创建者 Isaac Schlueter 将这一论点更进一步,呼吁 GitHub、npm 和 Microsoft ["完成这项工作"],彻底禁用非 MFA 发布,并默认将任何非 MFA 发布转换为分阶段发布。"你等待的每一天都是又一天的供应链安全失败,而你正是促成者,"他写道。
其他开发者对这些讨论并不信服。一条回复指出,促成令牌重置的 @antv 入侵是在 OIDC 发布可用的情况下发生的。另一条争论说,已经控制构建管道的攻击者可以简单地用 npm stage publish 替换 npm publish,仍然发送恶意版本。Khan 回应说,npm 的信任发布者设置可以完全阻止常规 npm publish,让分阶段流程成为唯一可行的路径。
维护者和消费者现在应该做什么
在重置后 CI/CD 管道出现故障的维护者需要生成新的精细访问令牌并更新其存储的密钥。任何怀疑在最近的 Mini Shai-Hulud 浪潮中暴露的人都应该轮换受影响环境范围内的每个凭证,而不仅仅是 npm 令牌。蠕虫的有效载荷会收集 GitHub 令牌、AWS、GCP 和 Azure 凭证、SSH 密钥、Kubernetes 令牌、Vault 令牌和 Stripe 密钥,以及 AI 工具配置文件如 .claude/settings.json。
对于消费者,今年早些时候发布的 minimumReleaseAge 设置仍然是避免新被污染版本的最直接杠杆。pnpm 11 本月早些时候开启了默认一天的发布年龄窗口。同一控制现在在 npm、Yarn 和 Bun 上都可用了。
令牌重置解决了蠕虫已经收集的凭证。分阶段发布解决了发布路径本身,采用可选方式。接下来的发展取决于有多少维护者在又一波 Mini Shai-Hulud 出现之前将新的审批步骤配置好。