Back to Blog
high SEVERITY6 min read

How package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age happens in pnpm workspaces and how to fix it

A pnpm workspace configuration was missing the `minimumReleaseAge` setting, allowing freshly published (and potentially malicious) package versions to be installed immediately. The fix adds a 7-day quarantine period along with `blockExoticSubdeps` and `trustPolicy: no-downgrade` to harden the supply chain against package takeover attacks.

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

Answer Summary

The vulnerability is a missing `minimumReleaseAge` setting in a pnpm-workspace.yaml file (CWE-829: Inclusion of Functionality from Untrusted Control Sphere). Without this setting, pnpm will immediately install newly published package versions, which may be malicious (e.g., from account takeovers or typosquatting). The fix adds `minimumReleaseAge: 10080` (7 days in minutes), `blockExoticSubdeps: true`, and `trustPolicy: no-downgrade` to the workspace configuration, creating a quarantine window that allows the community to detect and report compromised packages before they reach your project.

Vulnerability at a Glance

cweCWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
fixAdded `minimumReleaseAge: 10080`, `blockExoticSubdeps: true`, and `trustPolicy: no-downgrade`
riskSupply chain attack via freshly published malicious packages
languageYAML (pnpm configuration)
root causepnpm-workspace.yaml lacked minimumReleaseAge, blockExoticSubdeps, and trustPolicy settings
vulnerabilityMissing minimum release age in pnpm workspace configuration

How Missing minimumReleaseAge in pnpm Workspaces Enables Supply Chain Attacks

Introduction

In a Node.js library's pnpm-workspace.yaml, we discovered a HIGH severity supply chain hardening gap at line 1. The workspace configuration defined packages and a catalog but completely lacked any supply chain protection settings — no minimumReleaseAge, no blockExoticSubdeps, and no trustPolicy. For a library consumed by downstream users, this means that any time a maintainer runs pnpm install or updates dependencies, freshly published (and potentially compromised) package versions could be pulled in without any quarantine period.

Here's what the vulnerable configuration looked like:

packages:
  - "packages/*"
  - "packages/create-ziko/templates/*"
catalog:
  vite: "^8.2.2"

This configuration handles workspace package resolution and dependency cataloging, but it provides zero defense against supply chain poisoning — one of the most rapidly growing attack vectors in the JavaScript ecosystem.

The Vulnerability Explained

What's Actually Missing

The minimumReleaseAge setting, introduced in pnpm v10.16.0, tells pnpm to refuse installing any package version that was published less than a specified number of minutes ago. Without it, pnpm's default behavior is to install the latest matching version immediately — even if it was published seconds ago.

This matters because supply chain attacks follow a predictable pattern:

  1. An attacker gains access to a maintainer's npm account (credential theft, expired 2FA, social engineering)
  2. They publish a malicious version of the package
  3. Within minutes, thousands of CI/CD pipelines and developer machines pull the compromised version
  4. The malicious code exfiltrates secrets, installs backdoors, or compromises build artifacts

The window between publication and detection is typically hours to days. The ua-parser-js incident in 2021, the colors and faker incidents in 2022, and the xz-utils backdoor in 2024 all exploited this gap.

Attack Scenario Specific to This Project

This is a Node.js library with a monorepo structure (packages/* and packages/create-ziko/templates/*). Consider this attack path:

  1. The catalog pins vite: "^8.2.2" — this means any version from 8.2.2 up to (but not including) 9.0.0 is acceptable
  2. An attacker compromises the vite npm account and publishes vite@8.2.3 with a postinstall script that exfiltrates ~/.npmrc tokens
  3. A maintainer runs pnpm update — the malicious vite@8.2.3 is installed immediately
  4. The library's build artifacts could be poisoned, affecting every downstream consumer
  5. Template files in packages/create-ziko/templates/* could generate projects with the compromised dependency baked in

Without minimumReleaseAge, there is literally zero delay between a malicious publish and its installation.

The Fix

The fix adds three supply chain hardening directives to pnpm-workspace.yaml:

Before (Vulnerable)

packages:
  - "packages/*"
  - "packages/create-ziko/templates/*"
catalog:
  vite: "^8.2.2"

After (Hardened)

packages:
  - "packages/*"
  - "packages/create-ziko/templates/*"
catalog:
  vite: "^8.2.2"
minimumReleaseAge: 10080
blockExoticSubdeps: true
trustPolicy: no-downgrade

Breakdown of Each Setting

minimumReleaseAge: 10080 (7 days in minutes)

This is the primary defense. pnpm will now refuse to install any package version published less than 7 days ago. This provides a quarantine window during which:
- The npm security team can detect and remove malicious packages
- The community can report suspicious versions
- Automated security scanners can flag compromised releases
- The legitimate maintainer can notice unauthorized publishes

blockExoticSubdeps: true

This prevents subdependencies from using exotic protocols like git:, file:, or link: references. Attackers sometimes compromise a package to add a subdependency pointing to a malicious git repository. This setting blocks that vector entirely.

trustPolicy: no-downgrade

This prevents version downgrades, which is an attack vector where an attacker publishes a "new" version with a lower semver to exploit resolution quirks, or where a compromised lockfile attempts to downgrade to a known-vulnerable version.

Prevention & Best Practices

1. Always Set minimumReleaseAge in Production Projects

For libraries consumed by others, 7 days (10080 minutes) is the recommended minimum. For internal applications with less tolerance for delay, even 3 days (4320 minutes) provides significant protection.

2. Layer Your Defenses

Supply chain security requires defense in depth:
- minimumReleaseAge: Quarantine new versions
- blockExoticSubdeps: Block exotic protocol attacks
- trustPolicy: no-downgrade: Prevent downgrade attacks
- Lockfiles: Pin exact versions in CI
- npm audit / pnpm audit: Check for known vulnerabilities

3. Audit Your Workspace Configuration

Run this check in your CI pipeline:

grep -q "minimumReleaseAge" pnpm-workspace.yaml || echo "WARNING: No minimumReleaseAge set!"

4. Use Semgrep for Configuration Scanning

Static analysis tools like Semgrep can detect missing security settings in configuration files, not just code. The rule package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age specifically catches this pattern.

5. Monitor for pnpm Security Features

pnpm is actively adding supply chain hardening features. Stay current with their settings documentation and adopt new protections as they become available.

Key Takeaways

  • The pnpm-workspace.yaml catalog pinning vite: "^8.2.2" is insufficient protection — semver ranges allow any matching version, including freshly published malicious ones
  • A 7-day quarantine (minimumReleaseAge: 10080) would have blocked every major npm supply chain attack in recent history, as all were detected and removed within days
  • Node.js libraries are high-value targets because a single compromised library dependency propagates to all downstream consumers via packages/create-ziko/templates/*
  • blockExoticSubdeps: true closes the git/file protocol attack vector that bypasses registry-level protections entirely
  • trustPolicy: no-downgrade prevents a subtle attack class where lockfile manipulation forces installation of older, vulnerable versions

How Orbis AppSec Detected This

  • Source: npm registry packages resolved during pnpm install, including vite: "^8.2.2" from the catalog and all transitive dependencies of packages in packages/*
  • Sink: The pnpm-workspace.yaml configuration file at line 1, which controls dependency resolution behavior for the entire monorepo
  • Missing control: No minimumReleaseAge setting to quarantine newly published packages, no blockExoticSubdeps to prevent exotic protocol subdependencies, and no trustPolicy to prevent version downgrades
  • CWE: CWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
  • Fix: Added minimumReleaseAge: 10080, blockExoticSubdeps: true, and trustPolicy: no-downgrade to enforce a 7-day quarantine period and block exotic dependency protocols

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

Supply chain attacks are no longer theoretical — they're happening weekly across the npm ecosystem. The minimumReleaseAge setting in pnpm v10.16.0+ is one of the most impactful single-line changes you can make to protect your project. For a library like this one, where compromised dependencies propagate to every downstream consumer through templates and packages, the 7-day quarantine window is essential. Combined with blockExoticSubdeps and trustPolicy: no-downgrade, these three lines transform pnpm-workspace.yaml from a passive configuration file into an active supply chain defense layer.

Don't wait for an incident to harden your workspace configuration. The fix is three lines of YAML.

References

Frequently Asked Questions

What is a minimum release age vulnerability in pnpm?

It occurs when a pnpm workspace configuration doesn't enforce a waiting period before installing newly published package versions, allowing potentially malicious or unstable packages to be installed immediately after publication.

How do you prevent supply chain attacks in pnpm?

Set `minimumReleaseAge: 10080` in pnpm-workspace.yaml to enforce a 7-day quarantine, combine with `blockExoticSubdeps: true` to prevent exotic subdependency protocols, and use `trustPolicy: no-downgrade` to block version downgrades.

What CWE is missing minimum release age?

CWE-829: Inclusion of Functionality from Untrusted Control Sphere, as the application includes code from an external source (npm registry) without adequate verification of its trustworthiness.

Is using a lockfile enough to prevent supply chain attacks?

No. While lockfiles pin exact versions, they don't protect against malicious updates when you run `pnpm update` or add new dependencies. The minimumReleaseAge setting provides an additional layer by quarantining new releases regardless of lockfile state.

Can static analysis detect missing pnpm security settings?

Yes. Tools like Semgrep can scan pnpm-workspace.yaml files for missing security configurations such as minimumReleaseAge, blockExoticSubdeps, and trustPolicy using custom rules.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #8

Related Articles

critical

How CORS Misconfiguration happens in Node.js with Hono and how to fix it

CVE-2026-54290 is a HIGH severity CORS misconfiguration in the Hono web framework where the CORS middleware incorrectly reflects any `Origin` header back to the client — including credentials — when the `origin` option defaults to a wildcard. Upgrading `hono` from `4.12.16` to `4.12.34` in `package-lock.json` and pinning the version via `overrides` in `package.json` closes the vulnerability. Left unpatched, this flaw could allow malicious cross-origin sites to make credentialed requests and read

high

How Denial of Service via Infinite Loop happens in Node.js and how to fix it

A critical Denial of Service vulnerability (CVE-2026-67213) in the nanoid package allowed attackers to trigger infinite loops during random ID generation. This fix upgrades nanoid from version 3.3.11 to 3.3.18 using npm overrides, eliminating the infinite loop condition in the customAlphabet function that could crash Node.js applications.

critical

How WebSocket Protocol Handler Vulnerabilities happen in Node.js Dependencies and how to fix it

A critical vulnerability (CVE-2026-54466) was discovered in websocket-driver version 0.7.4, a WebSocket protocol handler used in the dependency tree. The vulnerability allowed attackers to exploit flaws in WebSocket frame parsing, potentially leading to denial of service or protocol-level attacks. The fix upgraded websocket-driver to version 0.7.5, which patches the protocol handling vulnerabilities and hardens input validation for untrusted WebSocket frames.

high

How Silent Form Limit Bypasses Happen in Starlette and How to Fix Them

CVE-2026-54283 is a high-severity Denial of Service vulnerability in Starlette where form size limits set on `request.form()` were silently ignored for `application/x-www-form-urlencoded` content, allowing attackers to submit arbitrarily large payloads that could exhaust server resources. The fix upgrades Starlette from version 0.49.1 to 0.50.0, where the form parser correctly enforces configured limits for both multipart and URL-encoded content types. This change was applied to `agent/sandbox/u

critical

How Server-Side Request Forgery (SSRF) Happens in Node.js fetch Tools and How to Fix It

A critical Server-Side Request Forgery (SSRF) vulnerability in `plugins/tools/fetch.js` allowed attackers to access internal resources and cloud metadata endpoints by passing arbitrary URLs to the fetch command. The fix adds hostname resolution and private IP range validation before executing any HTTP requests, preventing attackers from targeting internal infrastructure.

high

How IP Address Parsing Inconsistencies Cause SSRF and Trust-Boundary Bypass in Node.js Applications

The `ip-address` library version 10.2.0 contained a critical parsing inconsistency where the `Address4` decoder interpreted leading-zero octets as decimal numbers, while most DNS resolvers and network systems interpreted them as octal. This mismatch allowed attackers to bypass IP-based access controls and SSRF filters. Upgrading to version 10.3.1 fixes this vulnerability by aligning the library's parsing behavior with standard resolver behavior.