近来针对开发者的供应链攻击越来越频繁,且规模也在变大,比如最近的 Mini Shai-Hulud 供应链攻击事件 中,顶级项目的开发者也难以避免,事后攻击发起者黑客团队 TeamPCP 居然将攻击代码开源了(现已被 GitHub 下架),使得攻击更为容易。
不过一般攻击窗口时间都很短暂,只要不在相关时间内安装对应软件包即可避免。 pnpm 就提供了这一特性,minimumReleaseAge 是 pnpm 用来降低 npm 供应链攻击风险的配置。它的作用是:一个包的新版本发布后,必须经过指定分钟数,pnpm 才允许解析和安装它。
pnpm 官方说明该配置适用于所有依赖,包括传递依赖;它从 pnpm v10.16.0 开始加入,在 pnpm v11 中默认值变为 1440,也就是 1 天。
1. 为什么需要 minimumReleaseAge
很多供应链攻击的套路是:攻击者盗取维护者账号或发布流程,立刻发布一个恶意版本。恶意版本通常会在社区、平台或安全工具发现后被下架。pnpm 官方也建议通过 “延迟更新依赖” 降低安装受污染版本的概率,并说明延迟 24 小时通常可以避开许多高风险窗口。
1 | minimumReleaseAge: 1440 |
表示只安装发布时间至少超过 1440 分钟,也就是 24 小时 的版本:
2. 前置条件:确认 pnpm 版本
minimumReleaseAge 从 pnpm v10.16.0 开始支持。
先检查当前版本:
1 | pnpm -v |
目前 pnpm 已发布 v11.1.3 版本,该配置默认就是 1440 。
如果项目里还没有固定 pnpm 版本,可以在 package.json 中添加:
1 | { |
注意 pnpm v11 要求 Node.js 22+
3. 把时间设置为一周
pnpm v11 在项目根目录会创建 pnpm-workspace.yaml 文件,可以直接修改该文件进行配置。
我们可以把时间设置为一周的时间 1440*7 = 10080
1 | minimumReleaseAge: 10080 |
4. 常见取值
minimumReleaseAge 的单位是 分钟 。
| 场景 | 配置值 | 含义 |
|---|---|---|
| 不启用延迟 | 0 |
立即允许安装新版本 |
| 保守开发环境 | 60 |
延迟 1 小时 |
| 推荐默认值 | 1440 |
延迟 1 天 |
| 更严格生产环境 | 2880 |
延迟 2 天 |
| 高安全项目 | 10080 |
延迟 7 天 |
5. 为特定依赖设置例外
有些包可能需要紧急升级,比如安全修复、内部包、框架核心包。这时可以使用 minimumReleaseAgeExclude 。
5.1 排除指定包
1 | minimumReleaseAge: 1440 |
这表示:大多数依赖必须发布满 1 天才能安装,但 webpack 和 react 可以立即安装。pnpm 官方文档 说明,minimumReleaseAgeExclude 会按包名排除,并作用于该包的所有版本。
5.2 排除组织作用域包
从 pnpm v10.17.0 开始, minimumReleaseAgeExclude 支持模式匹配。
例如,允许公司内部包立即安装:
1 | minimumReleaseAge: 1440 |
5.3 只排除特定版本
从 pnpm v10.19.0 开始,minimumReleaseAgeExclude 支持精确版本,也支持用 || 写多个版本。
1 | minimumReleaseAge: 1440 |
这比直接排除整个包更安全,适合临时放行某个已验证版本。
6. 推荐的项目配置模板
下面是一份适合团队项目直接落地的配置:
1 | packages: |
minimumReleaseAgeStrict 是 pnpm v11 新增的行为控制项。官方文档说明:当没有版本满足 minimumReleaseAge 约束时, true 会让解析失败, false 则允许回退到不满足约束的版本;如果你显式配置了 minimumReleaseAge ,严格模式默认开启。
7. 在 CI 中引入
CI 里建议同时做两件事:
第一,固定 pnpm 版本:
1 | { |
第二,使用锁文件安装:
1 | pnpm install --frozen-lockfile |
这样 CI 不会随意解析新版本, minimumReleaseAge 主要会在新增依赖、更新依赖、刷新 lockfile 时发挥作用。
典型 GitHub Actions 示例:
1 | name: CI |
8. 如何验证配置是否生效
可以尝试安装一个刚发布不久的版本:
1 | pnpm add 某个刚发布的包@latest |
如果该包版本发布时间没有达到配置的分钟数,pnpm 会避免解析该版本,或者在严格模式下直接失败。
更常见的验证方式是在更新依赖时观察 lockfile:
1 | pnpm update |
如果最新版本太新,pnpm 不会马上把它写入 pnpm-lock.yaml。
9. 常见问题
Q1: minimumReleaseAge 会影响传递依赖吗?
会。pnpm 官方文档明确说明该配置适用于所有依赖,包括传递依赖。
Q2 :pnpm v11 还需要手动配置吗?
pnpm v11 默认 minimumReleaseAge: 1440,也就是默认延迟 1 天。
如果你想更严格,需要手动改成 2880 或 10080;如果你想关闭,可以设置为:
1 | minimumReleaseAge: 0 |
pnpm 官方供应链安全文档也说明,在 pnpm v11 中该值默认是 1440,如需退出该行为,可在 pnpm-workspace.yaml 中设置为 0。
Q3 :急需升级安全补丁怎么办?
推荐只临时放行具体版本:
1 | minimumReleaseAge: 1440 |
处理完成后,再删除这个例外。
Q4:私有 registry 没有发布时间怎么办?
pnpm v11 提供了 minimumReleaseAgeIgnoreMissingTime。当为 true 时,如果 registry 元数据没有 time 字段,pnpm 会跳过该包的 minimumReleaseAge 检查;如果设为 false,则在缺失时间信息时失败。
更严格的配置:
1 | minimumReleaseAge: 1440 |
10. 最佳实践总结
推荐从这个配置开始:
1 | minimumReleaseAge: 1440 |
如果是 monorepo 或企业项目,可以加上内部包例外:
1 | packages: |
11. 其他包管理器如何设置
- npm : 在
.npmrc中,min-release-age=X。X 是 天 的数量。需要 npmv11.10.0或更高版本。 - Yarn : 在
.yarnrc.yml中,设置npmMinimalAgeGate: X。
X 是持续时间(支持的日期单位是 ms, s, m, h, d, w,例如 7d)。如果没有指定持续时间,则解析为分钟(即 npmMinimalAgeGate: 1440 等于 npmMinimalAgeGate: 1440m)。需要Yarn v4.11或更高版本 - Bun : 在
bunfig.toml中,设置:X 是秒数。需要 Bun1
2
3[install]
minimumReleaseAge = Xv1.3.0或更高版本。
评论