How Missing pnpm Trust Policy and Release Age Settings Happen in Node.js Workspaces and How to Fix Them
Vulnerability at a Glance
| Field | Detail |
|---|---|
| Vulnerability | Missing pnpm Trust Policy and Minimum Release Age |
| CWE | CWE-1188: Insecure Default Initialization of Resource |
| Language | YAML / Node.js |
| Risk | Malicious or unstable packages installed without delay or downgrade protection |
| Root Cause | pnpm-workspace.yaml lacked trustPolicy, minimumReleaseAge, and blockExoticSubdeps |
| Fix | Added all three settings to pnpm-workspace.yaml |
Introduction
The pnpm-workspace.yaml file is the control plane for a pnpm monorepo — it defines which directories contain packages and, critically, governs the security posture of every dependency installation across the entire workspace. In this project, the file defined two workspace globs (apps/* and packages/*) but said nothing about how to trust or when to install the packages it resolves. That silence is the vulnerability.
Without explicit trustPolicy and minimumReleaseAge directives, pnpm's defaults leave the workspace open to two distinct supply chain attack vectors: a malicious package update that silently downgrades security settings, and a freshly published package version — potentially compromised before anyone notices — being pulled in the moment it hits the npm registry. For a private Node.js application where all risk lands on the application's own runtime, both vectors are directly exploitable.
The Vulnerability Explained
What was missing in pnpm-workspace.yaml
Before the fix, the entire configuration was:
packages:
- "apps/*"
- "packages/*"
Three security-relevant settings were absent:
trustPolicy— controls whether a package update is allowed to weaken the workspace's own security configuration. Without it, pnpm uses its default permissive behavior.minimumReleaseAge— sets a minimum age (in minutes) that a package version must reach before pnpm will install it. Without it, a version published 30 seconds ago is just as eligible as one published two years ago.blockExoticSubdeps— prevents resolution of subdependencies from unusual or non-standard sources that could bypass normal integrity checks.
How each missing setting creates risk
Missing trustPolicy
The trustPolicy setting, introduced in pnpm v10.21.0, governs whether a package can influence the trust level of the workspace itself. Setting it to no-downgrade means that even if a malicious package attempts to manipulate lifecycle scripts or configuration in a way that reduces security controls, pnpm will refuse the downgrade.
Without this setting, an attacker who compromises a transitive dependency could publish an update that weakens the workspace's security posture — for example, by enabling lifecycle scripts that were previously restricted, or by altering resolution strategies in ways that benefit subsequent attack steps.
Missing minimumReleaseAge: 10080
The value 10080 is the number of minutes in seven days. This is a deliberate choice: the npm ecosystem has historically seen malicious packages discovered and removed within hours to days of publication. A 7-day quarantine window means that by the time pnpm will install a newly published version, it has had time to be:
- Scanned by automated tools across the ecosystem
- Reviewed by security researchers
- Flagged if it contains malicious code
A real-world example of why this matters: the event-stream incident in 2018 involved a malicious version published to npm that was installed by thousands of projects within days. A minimumReleaseAge of 10080 minutes would have prevented automatic installation of that version during its most dangerous window.
In this workspace, any package under apps/* or packages/* that lists a dependency without a pinned version could silently pull in a brand-new, unvetted release on the next pnpm install.
Missing blockExoticSubdeps
Without blockExoticSubdeps: true, pnpm may resolve subdependencies from non-standard sources — git URLs, local paths in unusual forms, or other exotic specifiers — that bypass the normal npm registry integrity pipeline. Blocking these closes a resolution pathway that could be exploited by a compromised direct dependency that injects exotic subdependency specifiers.
The Fix
The fix adds three lines to pnpm-workspace.yaml:
Before
packages:
- "apps/*"
- "packages/*"
After
packages:
- "apps/*"
- "packages/*"
minimumReleaseAge: 10080
blockExoticSubdeps: true
trustPolicy: no-downgrade
What each line does
minimumReleaseAge: 10080
Instructs pnpm to refuse installation of any package version published less than 10,080 minutes (7 days) ago. This applies workspace-wide, covering every package resolved under apps/* and packages/*. It does not affect already-installed versions or versions older than 7 days — only net-new version resolutions are gated.
blockExoticSubdeps: true
Prevents any subdependency from being resolved via exotic specifiers (non-standard git refs, unusual path formats, etc.). This closes a resolution vector that could be used by a compromised dependency to inject unexpected code through its own dependency tree.
trustPolicy: no-downgrade
Enforces a security floor: the workspace's trust configuration cannot be weakened by any package update. If a package attempts to lower the effective trust level, pnpm will reject it. This is the direct mitigation for the flagged vulnerability type.
Why all three together?
Each setting addresses a different phase of a supply chain attack:
minimumReleaseAgeblocks the initial delivery of a malicious package versionblockExoticSubdepsblocks lateral movement through exotic subdependency resolutiontrustPolicy: no-downgradeblocks privilege reduction after a package is installed
Together, they form a layered defense within the package manager itself.
Prevention & Best Practices
1. Treat pnpm-workspace.yaml as a security boundary, not just a layout file
Most developers configure pnpm-workspace.yaml once and never revisit it. As pnpm adds security-relevant settings (v10.16.0 added minimumReleaseAge, v10.21.0 added trustPolicy), older workspace files silently miss these protections. Audit your workspace configuration every time you upgrade pnpm.
2. Combine package manager hardening with lockfile integrity
pnpm-workspace.yaml hardening complements but does not replace a committed pnpm-lock.yaml. Use both:
- The lockfile pins exact versions for reproducibility
- minimumReleaseAge and trustPolicy add runtime policy enforcement on top of those pins
3. Use Semgrep rules for pnpm configuration drift
The rule that flagged this issue — package_managers.pnpm.pnpm-trust-policy.pnpm-trust-policy — is part of a family of pnpm-specific Semgrep checks. Adding these to your CI pipeline catches configuration drift before it reaches production:
# .github/workflows/security.yml
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
config: "p/supply-chain"
4. Apply the principle of least privilege to package resolution
trustPolicy: no-downgrade is the package manager equivalent of "never reduce your own permissions." Apply the same thinking to:
- npm/yarn equivalent settings (audit flags, ignore-scripts)
- Dependency allowlists in your CI pipeline
- SBOM generation and monitoring
5. Reference security standards
- CWE-1188: Insecure Default Initialization of Resource — the root cause here is that pnpm's defaults are permissive, and the workspace config did not override them.
- OWASP A06:2021 – Vulnerable and Outdated Components: Using packages without a release-age filter increases exposure to newly introduced vulnerabilities.
- SLSA Supply Chain Levels: These settings contribute to SLSA L2/L3 by adding provenance and integrity controls at the dependency resolution layer.
Key Takeaways
pnpm-workspace.yamlis a security-relevant file, not just a monorepo layout descriptor — missing hardening settings here affect every package inapps/*andpackages/*.minimumReleaseAge: 10080creates a 7-day quarantine window that gives the ecosystem time to detect and flag malicious package versions before your workspace installs them.trustPolicy: no-downgradeenforces a security floor — it prevents any package from weakening the workspace's own trust configuration, closing a downgrade attack vector.blockExoticSubdeps: truecloses an often-overlooked resolution pathway through which a compromised direct dependency could inject code via exotic subdependency specifiers.- These settings have zero impact on valid, trusted dependencies — packages older than 7 days from standard registry sources are completely unaffected by all three additions.
How Orbis AppSec Detected This
- Source: The
pnpm-workspace.yamlfile at line 1 — specifically, the absence of security directives in a workspace configuration that governs all dependency resolution for the monorepo. - Sink: Any
pnpm installorpnpm updateinvocation that resolves packages underapps/*orpackages/*without a trust or release-age policy in effect. - Missing control: No
trustPolicy,minimumReleaseAge, orblockExoticSubdepsdirective was present, leaving pnpm's permissive defaults in place for the entire workspace. - CWE: CWE-1188 — Insecure Default Initialization of Resource (the resource being the pnpm workspace's security configuration).
- Fix: Added
trustPolicy: no-downgrade,minimumReleaseAge: 10080, andblockExoticSubdeps: truetopnpm-workspace.yaml, enforcing a security floor, a 7-day release quarantine, and exotic subdependency blocking across the entire workspace.
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 three-line addition to pnpm-workspace.yaml closes three distinct supply chain attack vectors that would otherwise be silently present in every pnpm install run. The missing trustPolicy: no-downgrade setting was the primary flagged vulnerability, but the fix correctly addresses the full surface: delivery (release age), resolution (exotic subdeps), and privilege (trust policy). For any Node.js monorepo using pnpm v10.16.0 or later, these settings should be considered baseline hardening — not optional extras. Supply chain attacks against the npm ecosystem are active and ongoing; raising the bar within your package manager configuration is one of the highest-leverage, lowest-cost defenses available.