Back to Blog
high SEVERITY6 min read

How pnpm Missing Minimum Release Age happens in Node.js workspaces and how to fix it

A pnpm workspace configuration had `minimumReleaseAge` set to `0`, meaning newly published npm packages could be installed immediately—before the community has time to detect malicious or compromised releases. By changing this value to `10080` (seven days in minutes), the project now enforces a quarantine window that dramatically reduces exposure to typosquatting, dependency confusion, and post-publish malware injection attacks.

O
By Orbis AppSec
Published August 26, 2026Reviewed August 26, 2026

Answer Summary

This vulnerability is a missing minimum release age in a pnpm workspace configuration (`pnpm-workspace.yaml`), which maps to supply chain security risks (CWE-1357: Reliance on Insufficiently Trustworthy Component). With `minimumReleaseAge: 0`, pnpm will immediately install any newly published package version, including malicious packages published seconds before a `pnpm install` run. The fix is to set `minimumReleaseAge: 10080` in `pnpm-workspace.yaml`, which tells pnpm to refuse installing any package version published within the last 7 days (10,080 minutes), giving the security community time to detect and respond to malicious releases.

Vulnerability at a Glance

cweCWE-1357
fixSet `minimumReleaseAge: 10080` to enforce a 7-day waiting period before new package versions can be installed
riskImmediate installation of newly published, potentially malicious package versions
languageYAML / Node.js (pnpm)
root cause`minimumReleaseAge: 0` in `pnpm-workspace.yaml` disables the quarantine window for new package releases
vulnerabilityMissing Minimum Release Age (Supply Chain Risk)

The Risk Hidden in a Single Zero

In a Node.js library's pnpm-workspace.yaml, a single configuration line read:

minimumReleaseAge: 0

That zero is not a neutral default—it is an open door. It tells pnpm: install any package version the moment it appears on the npm registry, no matter how new it is. For a project that downstream consumers depend on, this setting means that a supply chain attack targeting a transitive dependency could propagate to production systems within minutes of the malicious package being published.

This post explains what the minimumReleaseAge setting does, why the value 0 is dangerous, and how setting it to 10080 (seven days in minutes) closes a real attack vector that has been exploited in the wild.


The Vulnerability Explained

What minimumReleaseAge Controls

pnpm v10.16.0 introduced the minimumReleaseAge setting in workspace configuration. It accepts a value in minutes and instructs pnpm to refuse resolving any package version that was published to the npm registry more recently than that threshold.

When set to 0, the feature is effectively disabled—pnpm will happily resolve and install a package version published 30 seconds ago.

The Vulnerable Configuration

Here is the configuration as it existed before the fix, in pnpm-workspace.yaml at line 5:

allowBuilds:
  esbuild: true
  unrs-resolver: true
  vue-demi: true
minimumReleaseAge: 0

The allowBuilds section is correctly configured, but the minimumReleaseAge: 0 line actively opts out of the quarantine window.

How This Gets Exploited

The npm ecosystem has seen a consistent pattern of attacks that this setting directly mitigates:

  1. Account takeover / credential stuffing: An attacker compromises a maintainer's npm credentials and publishes a new patch version (e.g., some-util@2.3.1) containing malicious code. With minimumReleaseAge: 0, the next pnpm install or CI run picks it up immediately.

  2. Typosquatting and dependency confusion: A new package with a name close to a popular one is published. Automated bots and CI pipelines that run installs frequently are the first victims.

  3. Protestware / supply chain sabotage: A maintainer intentionally injects malicious code into a new version. The 7-day window gives the community time to discover, report, and for registries to yank the package.

Real-World Impact for This Repository

This file is in a Node.js library that downstream consumers install. If a malicious version of a dependency were installed into this library's build or test pipeline, it could:

  • Exfiltrate environment variables (CI secrets, npm tokens, cloud credentials) during pnpm install
  • Tamper with the built output that gets published to npm, affecting all downstream users
  • Execute arbitrary scripts via pnpm's allowBuilds lifecycle hooks (which are already enabled for esbuild, unrs-resolver, and vue-demi)

The combination of allowBuilds being enabled and minimumReleaseAge: 0 is particularly risky: build scripts run during install, so a malicious package that lands in the dependency tree can execute code immediately.


The Fix

The change is minimal but meaningful:

-minimumReleaseAge: 0
+minimumReleaseAge: 10080

Before:

allowBuilds:
  esbuild: true
  unrs-resolver: true
  vue-demi: true
minimumReleaseAge: 0

After:

allowBuilds:
  esbuild: true
  unrs-resolver: true
  vue-demi: true
minimumReleaseAge: 10080

Why 10080?

10080 is the number of minutes in seven days (7 × 24 × 60 = 10,080). This is the value recommended by the pnpm documentation and the value flagged by the Semgrep rule. Seven days is considered a reasonable window because:

  • Most malicious packages are detected and removed by npm's security team or community reporters within hours to days
  • Legitimate patch releases rarely need to be consumed within minutes; most projects can tolerate a week's delay on transitive dependency updates
  • Security researchers and automated scanning tools (like Socket.dev and Snyk) typically surface issues within this window

What pnpm Does With This Setting

When minimumReleaseAge: 10080 is set, pnpm checks the time field in a package's npm registry metadata during resolution. If the version's publish timestamp is less than 10,080 minutes ago, pnpm skips that version and resolves to the next-oldest version that satisfies the semver range. This happens transparently during pnpm install—no error, no manual intervention needed.


Prevention & Best Practices

1. Always Set minimumReleaseAge in New pnpm Workspaces

When creating a new pnpm-workspace.yaml, include this setting from day one:

minimumReleaseAge: 10080

It was added in pnpm v10.16.0, so ensure your team is on a recent enough version.

2. Combine With Other Supply Chain Controls

minimumReleaseAge is one layer. Pair it with:

  • Lockfiles committed to source control: Prevents unexpected resolution changes between installs
  • pnpm audit in CI: Catches known CVEs in the resolved dependency tree
  • Provenance attestation: Use packages published with npm provenance where available
  • Dependency review in PRs: Tools like Dependabot or Renovate can flag new dependency additions for human review

3. Audit Your allowBuilds List

This project enables build scripts for esbuild, unrs-resolver, and vue-demi. Each of these is a potential code execution point during install. Periodically review this list and remove entries for packages that no longer need it.

4. Static Analysis in CI

The Semgrep rule package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age detects this pattern automatically. Add it to your CI pipeline to catch regressions:

semgrep --config "p/supply-chain" pnpm-workspace.yaml

Relevant Standards

  • CWE-1357: Reliance on Insufficiently Trustworthy Component
  • OWASP A06:2021: Vulnerable and Outdated Components
  • SLSA Supply Chain Threats: Compromised dependency (threat D)

Key Takeaways

  • minimumReleaseAge: 0 is not a safe default—it actively disables a security control that pnpm provides specifically to combat supply chain attacks.
  • The combination of allowBuilds and minimumReleaseAge: 0 in this pnpm-workspace.yaml was especially risky: build scripts execute during install, so a newly published malicious package could run code immediately.
  • 10,080 minutes (7 days) is the recommended quarantine window because it aligns with the typical detection and response time for malicious npm packages.
  • Downstream consumers of this Node.js library were indirectly protected by this fix—a compromised build pipeline could have resulted in a tainted published package.
  • Static analysis tools like Semgrep can detect this in seconds—there is no reason to leave this misconfiguration undetected in a CI pipeline.

How Orbis AppSec Detected This

  • Source: The pnpm-workspace.yaml configuration file, which governs dependency resolution for all packages in the workspace
  • Sink: The minimumReleaseAge: 0 setting at line 5, which instructs pnpm to resolve and install package versions with no age restriction—including versions published seconds before an install run
  • Missing control: No minimum release age threshold was enforced, meaning newly published (potentially malicious) package versions were immediately eligible for installation
  • CWE: CWE-1357 — Reliance on Insufficiently Trustworthy Component
  • Fix: Changed minimumReleaseAge from 0 to 10080 in pnpm-workspace.yaml, enforcing a 7-day quarantine window on all newly published package versions

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

A single zero in a YAML configuration file was all it took to leave this Node.js library's dependency resolution wide open to supply chain attacks. The fix—changing minimumReleaseAge: 0 to minimumReleaseAge: 10080—took one line but added a meaningful, automated defense layer against one of the most active attack categories targeting the npm ecosystem today.

Supply chain attacks are not theoretical. The npm registry sees malicious packages published regularly, and the attack window between publish and detection is often measured in hours. A 7-day quarantine window, enforced automatically by pnpm, is a low-friction, high-value control that every workspace should have enabled.

If your project uses pnpm, open your pnpm-workspace.yaml right now and check whether minimumReleaseAge is set. If it is missing or set to 0, you have the same vulnerability this PR just fixed.


References

Frequently Asked Questions

What is a missing minimum release age in pnpm?

It means pnpm is configured to allow installation of package versions the moment they are published to the npm registry, with no waiting period. This creates a window where malicious or compromised packages can be installed before the community detects them.

How do you prevent supply chain attacks via new package versions in pnpm?

Add `minimumReleaseAge: 10080` to your `pnpm-workspace.yaml` file. This tells pnpm to skip any package version published within the last 7 days (10,080 minutes), giving the ecosystem time to flag malicious releases.

What CWE is missing minimum release age?

CWE-1357 (Reliance on Insufficiently Trustworthy Component) is the closest match, as the root issue is trusting newly published, unvetted package versions without a quarantine period.

Is locking package versions with a lockfile enough to prevent this?

A lockfile protects against unexpected version changes in existing installs, but it does not protect you when you first add a dependency or when a maintainer's account is compromised and a new version is published. `minimumReleaseAge` adds a complementary layer of defense.

Can static analysis detect missing minimum release age?

Yes. Semgrep rule `package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age` detects this pattern by checking whether `minimumReleaseAge` is absent or set to `0` in `pnpm-workspace.yaml`.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #896

Related Articles

high

How Denial of Service via infinite loop happens in Node.js dependencies and how to fix it

A high-severity Denial of Service vulnerability in the nanoid package (CVE-2026-67213) was discovered in the project's dependency tree, where crafted input could trigger an infinite loop during random ID generation. The fix upgrades nanoid from 3.3.17 to 3.3.18 and adds an npm override to ensure all transitive dependencies use the patched version.

high

How Dependabot Missing Cooldown happens in GitHub Actions and how to fix it

A Dependabot configuration in `.github/dependabot.yml` was missing cooldown periods for both its npm and GitHub Actions package ecosystems, meaning newly published — potentially malicious or unstable — package versions could be proposed for adoption immediately after release. Adding a `cooldown` block with `default-days: 7` to each ecosystem entry creates a 7-day buffer, allowing the security community time to identify and flag compromised packages before they reach your codebase.

high

How pnpm Missing Minimum Release Age happens in Node.js workspaces and how to fix it

A missing `minimumReleaseAge` setting in `pnpm-workspace.yaml` left this Node.js workspace vulnerable to immediately installing newly published — potentially malicious — package versions. The fix adds `minimumReleaseAge: 10080` (7 days in minutes) to enforce a quarantine window before any freshly published package can be installed. This single configuration change significantly reduces the risk of supply chain attacks targeting the package publishing pipeline.

high

How Dependabot Missing Cooldown happens in GitHub Actions and how to fix it

A high-severity misconfiguration in `.github/dependabot.yml` left three `package-ecosystem` entries without a cooldown period, meaning Dependabot could immediately propose updates from newly published—potentially malicious—packages. The fix adds a `cooldown` block with `default-days: 7` to each entry, introducing a mandatory waiting period before any newly released package version is surfaced as an update candidate. For a Node.js library whose vulnerabilities ripple downstream to all consumers,

critical

How Unauthenticated Proxy Endpoints Enable DoS Amplification in FastAPI and how to fix it

Public proxy endpoints in `backend/api/proxy.py` had no rate limiting, allowing any attacker to flood the httpx connection pool with unauthenticated requests and amplify denial-of-service attacks against downstream tile and coordinate-conversion services. The fix introduces a per-IP sliding-window rate limiter using environment-configurable thresholds, closing the amplification vector without breaking legitimate usage.

high

How Dependabot Missing Cooldown happens in GitHub Actions and how to fix it

A missing `cooldown` block in `.github/dependabot.yml` meant that Dependabot could immediately propose updates to newly published npm packages — including those that may be malicious, compromised, or unstable. By adding a `cooldown` with `default-days: 7`, the project now waits one week before surfacing new package versions, giving the security community time to detect and flag bad releases before they reach production.