一个 npm 包只能配一个 OIDC 发布配置,这曾经是合理的——直到今天这件事彻底变了

你的 npm 包有 stable、beta、staging 三套发布流程吗?如果是,那你大概率为其中至少一套留着一枚永远不会过期的 access token——一枚一旦泄露就能以你的名义向整个 npm 生态投毒的钥匙。这不是你的安全意识差,是以前的产品设计逼你做的选择。

2026 年 9 月 3 日,npm 正式解除了「每个包只能配一个 OIDC trusted publishing 配置」的限制。

这个限制为什么让人头疼

OIDC trusted publishing 的逻辑很干净:GitHub Actions workflow 在发布时请求一枚短效 token,npm 验证这枚 token 确实来自你声明的仓库和工作流,然后才允许发布。没有永久密钥需要管理,没有密钥轮换需要操心,每一次发布都可以溯源。这是目前最安全的 npm 发布方式。

但这个方案有一个前提:你的包只有一个发布入口。

现实中的包往往不止一个发布入口——release.yml 发稳定版、prerelease.yml 发 beta、rc.yml 发候选版本、staging.yml 发内部测试版本。在 9 月 3 日之前,一个包只能申请一枚 OIDC token 配置。多出来的那些路径,开发者只有两个选项:把全部流程硬塞进一个 workflow 文件里;或者保留一枚 long-lived access token(bypass2fa GAT),让自动化脚本在没有人类监督的情况下永久持有发布权限。

GitHub 官方在公告里直说:bypass2fa GAT 是他们最不想看到的结果。但以前的限制让很多维护者不得不走上这条路。

新的多配置模型是怎样的

现在,每个 npm 包可以拥有最多 10 套独立的 OIDC trusted publishing 配置,每套配置独立声明自己的仓库、workflow 和环境条件。三套配置之间完全平等,没有优先级、没有 deny 规则、没有顺序保证——任何一个配置匹配成功,发布即被授权。

这意味着:stable 发稳定版走一条 OIDC 认证路径,beta 发测试版走另一条,两条都安全,隔离运行,互相不影响。staging 配置可以保持仅入 staging 队列,需要人工审核后才能转正。

和单配置时代相比,多配置是纯增量的——它不会撤销任何已有的安全能力,只在它之上叠加。

staging 发布队列的新守卫

和这次更新一起落地的还有 staging 发布队列的一个 UI 改进:Approval 按钮在恶意软件扫描完成之前一直是禁用的,扫描通过后才变为可点击。

这个改动堵上了一个之前靠「文档提醒」来防守的漏洞——深夜匆忙发版的维护者可能在扫描结果出来之前就点了 Approval,多年形成的操作习惯成了供应链攻击的入口。现在这个风险被 UI 本身的约束结构直接物理消灭了。

npmjs.com 的 versions 标签页现在也同步更新了:每个版本都可以看到它经历了哪个阶段——approved、rejected 还是仍在 staging。

现在应该怎么做

如果你的包目前仍在用 long-lived access token,第一步不是在 Settings 页面里随便加个 OIDC 配置然后把旧 token 丢进回收站——而是先确认你的所有发布路径都被 OIDC 覆盖,再撤销旧 token。具体来说:

第一步:清点发布入口。 翻一翻你的 .github/workflows 目录,有多少个 workflow 会触发 npm publish?每个对应哪个发布类型?

第二步:为每个入口申请独立配置。 在 npmjs.com → 你的包 → Settings → Publish 相关设置里,逐个添加 OIDC 配置,每套配置对应一个 workflow 文件。不要让两套配置对应同一个 workflow——配置之间是平等且可叠加的,不存在「哪个优先」的概念。

第三步:staging 配置保持默认。 staging-only 模式下,即使 workflow 被劫持,恶意版本也只能躺在队列里等待人工审核,而审核按钮在扫描完成前不可点击。把这条作为所有非核心发布路径的默认状态。

第四步:确认无误后撤销旧 token。 在 npm → Access Tokens 页面找到所有 legacy token,Revoke 并确认 workflow 已经切换到 OIDC 模式。

一个包现在最多支持 10 套配置,实际上几乎覆盖了所有复杂发布的场景。如果你在用第 11 种发布路径,npm 团队表态愿意听取具体需求。

OIDC trusted publishing 替代的不是「是否安全」,而是「安全的代价有多大」。在多配置模式落地之后,这个代价正式归零了。

评论区

0 条评论

登录后可评论。