Supply chain attacks targeting developers have become increasingly frequent and larger in scale. For instance, in the recent Mini Shai-Hulud supply chain attack, even developers of top-tier projects were not immune. Shockingly, the hacking group TeamPCP, who initiated the attack, open-sourced their attack code (which has since been taken down by GitHub), making such attacks even easier to execute.
However, the attack window is typically short, meaning you can avoid being compromised simply by not installing the affected package version during that period. pnpm provides a built-in feature to address this: minimumReleaseAge is a configuration designed to mitigate npm supply chain attack risks. When set, any newly published package version must wait for a specified number of minutes before pnpm allows it to be resolved and installed.
According to the official pnpm documentation, this configuration applies to all dependencies, including transitive ones. It was introduced in pnpm v10.16.0, and starting with pnpm v11, its default value is set to 1440 (which equates to 1 day).
It is highly recommended for pnpm users to upgrade to v11: pnpm - Migrating from v10 to v11
1. Why minimumReleaseAge is Necessary
A common pattern in supply chain attacks is for attackers to hijack a maintainer's account or publishing workflow, then immediately release a malicious version. These malicious releases are usually taken down quickly once detected by the community, registry platforms, or security tools. The pnpm team suggests "delaying dependency updates" to lower the probability of installing contaminated versions, stating that a 24-hour delay is generally sufficient to avoid most high-risk windows.
1 | minimumReleaseAge: 1440 |
This specifies that pnpm should only install versions that have been published for at least 1440 minutes (24 hours):
2. Prerequisites: Confirm pnpm Version
minimumReleaseAge is supported starting from pnpm v10.16.0.
First, check your current version:
1 | pnpm -v |
Currently, pnpm has released v11.1.3, where this configuration defaults to 1440.
If your project does not have a pinned pnpm version yet, you can add it to your package.json:
1 | { |
Note: pnpm v11 requires Node.js 22+
3. Setting the Delay to One Week
In pnpm v11, a pnpm-workspace.yaml file is created at the project root. You can configure this setting directly in that file.
We can set the delay to one week (1440 * 7 = 10080):
1 | minimumReleaseAge: 10080 |
4. Common Configuration Values
The unit for minimumReleaseAge is minutes.
| Scenario | Value | Description |
|---|---|---|
| No delay | 0 |
Allows immediate installation of new versions |
| Conservative Dev Environment | 60 |
Delays by 1 hour |
| Recommended Default | 1440 |
Delays by 1 day |
| Stricter Production Environment | 2880 |
Delays by 2 days |
| High Security Projects | 10080 |
Delays by 7 days |
5. Setting Exclusions for Specific Dependencies
Some packages may require urgent upgrades, such as security patches, internal packages, or core framework packages. For these cases, you can use minimumReleaseAgeExclude.
5.1 Excluding Specific Packages
1 | minimumReleaseAge: 1440 |
This indicates that while most dependencies must be published for at least 1 day before installation, webpack and react can be installed immediately. As detailed in the pnpm documentation, minimumReleaseAgeExclude filters by package name and applies to all versions of that package.
5.2 Excluding Scoped Packages
Starting with pnpm v10.17.0, minimumReleaseAgeExclude supports pattern matching.
For example, allowing company internal packages to be installed immediately:
1 | minimumReleaseAge: 1440 |
5.3 Excluding Specific Versions
Starting with pnpm v10.19.0, minimumReleaseAgeExclude supports pinning specific versions, as well as using || to list multiple versions.
1 | minimumReleaseAge: 1440 |
This approach is safer than excluding the entire package, making it ideal for temporarily permitting a verified version.
6. Recommended Project Configuration Template
Below is a production-ready configuration template suitable for team projects:
1 | packages: |
minimumReleaseAgeStrict is a behavior control option introduced in pnpm v11. The documentation states that when no package version meets the minimumReleaseAge constraint, setting this to true causes dependency resolution to fail, whereas false allows falling back to versions that do not meet the constraint. If you explicitly configure minimumReleaseAge, strict mode is enabled by default.
7. Incorporating into CI
It is recommended to implement two practices in your CI pipeline:
First, pin the pnpm version:
1 | { |
Second, install using the lockfile:
1 | pnpm install --frozen-lockfile |
This ensures that CI does not arbitrarily resolve new package versions. Thus, minimumReleaseAge primarily plays a role when adding dependencies, updating packages, or updating the lockfile.
A typical GitHub Actions example:
1 | name: CI |
8. Verifying the Configuration
You can test this by trying to install a recently published version of a package:
1 | pnpm add <recently-published-package>@latest |
If the release time of the package version has not reached the configured duration in minutes, pnpm will avoid resolving that version or fail directly when strict mode is active.
A more common way to verify is to inspect the lockfile during dependency updates:
1 | pnpm update |
If the latest version is too new, pnpm will not write it to pnpm-lock.yaml.
9. FAQ
Q1: Does minimumReleaseAge affect transitive dependencies?
Yes. The official pnpm documentation explicitly states that this configuration applies to all dependencies, including transitive ones.
Q2: Is manual configuration still required in pnpm v11?
In pnpm v11, minimumReleaseAge defaults to 1440 (a 1-day delay).
If you wish to enforce stricter rules, you must manually change it to 2880 or 10080. If you wish to disable this feature, set it to:
1 | minimumReleaseAge: 0 |
The official pnpm supply chain security documentation also states that in pnpm v11, this value is 1440 by default. To opt out of this behavior, configure it to 0 in pnpm-workspace.yaml.
Q3: What if I need to upgrade an urgent security patch?
It is recommended to temporarily exclude the specific version only:
1 | minimumReleaseAge: 1440 |
Once the update is complete, you can remove this exception.
Q4: What if my private registry does not contain release timestamps?
pnpm v11 provides minimumReleaseAgeIgnoreMissingTime. When set to true, if the registry metadata lacks a time field, pnpm will bypass the minimumReleaseAge check for that package. If set to false, it will fail when time information is missing.
A stricter configuration:
1 | minimumReleaseAge: 1440 |
10. Summary of Best Practices
We recommend starting with the following configuration:
1 | minimumReleaseAge: 1440 |
For monorepos or enterprise projects, you can add exclusions for internal scoped packages:
1 | packages: |
11. How to Configure in Other Package Managers
- npm: In
.npmrc, setmin-release-age=X, whereXis the number of days. This requires npmv11.10.0or higher. - Yarn: In
.yarnrc.yml, setnpmMinimalAgeGate: X, whereXis the duration (supported duration units arems,s,m,h,d,w, e.g.,7d). If no unit is specified, it defaults to minutes (meaningnpmMinimalAgeGate: 1440is equivalent tonpmMinimalAgeGate: 1440m). This requires Yarnv4.11or higher. - Bun: In
bunfig.toml, configure the following:Where1
2
3[install]
minimumReleaseAge = XXis the duration in seconds. This requires Bunv1.3.0or higher.
Comments