Back to Blog
high SEVERITY8 min read

How Missing pnpm Trust Policy and Release Age Settings Happen in Node.js Workspaces and How to Fix Them

A pnpm workspace configuration was missing two critical security hardening settings — `trustPolicy` and `minimumReleaseAge` — leaving the project vulnerable to malicious package updates and newly published, potentially compromised package versions. The fix adds `trustPolicy: no-downgrade`, `minimumReleaseAge: 10080`, and `blockExoticSubdeps: true` to `pnpm-workspace.yaml`, raising the security bar against supply chain attacks. These settings, available since pnpm v10.16.0 and v10.21.0 respective

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

Answer Summary

This vulnerability involves missing security hardening settings in a pnpm workspace configuration file (`pnpm-workspace.yaml`). Specifically, the absence of `trustPolicy` (CWE-1188: Insecure Default Initialization) and `minimumReleaseAge` settings means the project could silently install newly published or downgraded malicious packages without any safeguard. The fix adds `trustPolicy: no-downgrade` to prevent security setting downgrades, `minimumReleaseAge: 10080` to enforce a 7-day waiting period on newly released package versions, and `blockExoticSubdeps: true` to block unusual subdependency resolution patterns — all in `pnpm-workspace.yaml`.

Vulnerability at a Glance

cweCWE-1188
fixAdded trustPolicy: no-downgrade, minimumReleaseAge: 10080, and blockExoticSubdeps: true to pnpm-workspace.yaml
riskMalicious or unstable packages can be installed without delay or security downgrade protection
languageYAML / Node.js
root causepnpm-workspace.yaml lacked trustPolicy, minimumReleaseAge, and blockExoticSubdeps settings
vulnerabilityMissing pnpm Trust Policy and Minimum Release Age

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:

  1. trustPolicy — controls whether a package update is allowed to weaken the workspace's own security configuration. Without it, pnpm uses its default permissive behavior.
  2. 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.
  3. 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:

  • minimumReleaseAge blocks the initial delivery of a malicious package version
  • blockExoticSubdeps blocks lateral movement through exotic subdependency resolution
  • trustPolicy: no-downgrade blocks 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.yaml is a security-relevant file, not just a monorepo layout descriptor — missing hardening settings here affect every package in apps/* and packages/*.
  • minimumReleaseAge: 10080 creates a 7-day quarantine window that gives the ecosystem time to detect and flag malicious package versions before your workspace installs them.
  • trustPolicy: no-downgrade enforces a security floor — it prevents any package from weakening the workspace's own trust configuration, closing a downgrade attack vector.
  • blockExoticSubdeps: true closes 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.yaml file at line 1 — specifically, the absence of security directives in a workspace configuration that governs all dependency resolution for the monorepo.
  • Sink: Any pnpm install or pnpm update invocation that resolves packages under apps/* or packages/* without a trust or release-age policy in effect.
  • Missing control: No trustPolicy, minimumReleaseAge, or blockExoticSubdeps directive 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, and blockExoticSubdeps: true to pnpm-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.


References

Frequently Asked Questions

What is a missing pnpm trust policy vulnerability?

It means the pnpm workspace configuration lacks a trustPolicy setting, allowing malicious package updates to potentially downgrade security controls without restriction.

How do you prevent missing trust policy issues in pnpm workspaces?

Add `trustPolicy: no-downgrade` and `minimumReleaseAge: 10080` to your `pnpm-workspace.yaml` file to enforce security floors and delay installation of newly published packages.

What CWE is associated with missing pnpm trust policy?

CWE-1188 (Insecure Default Initialization of Resource) applies, as the default pnpm workspace configuration does not enforce trust or release-age policies.

Is pinning package versions enough to prevent supply chain attacks in pnpm?

No. Pinning helps, but without trustPolicy and minimumReleaseAge, a compromised package version published to npm can still be installed before it is flagged as malicious.

Can static analysis detect missing pnpm trust policy settings?

Yes. Tools like Semgrep with pnpm-specific rules can detect the absence of trustPolicy and minimumReleaseAge in pnpm-workspace.yaml automatically.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #10

Related Articles

high

How Denial of Service via Unbounded Intermediate Arrays happens in JavaScript and how to fix it

CVE-2026-69152 is a high-severity Denial of Service vulnerability in the `brace-expansion` npm package (versions prior to 1.1.18/2.1.4/3.0.6/5.0.9) that allows attackers to crash a Node.js application by crafting glob patterns that generate unbounded intermediate arrays, effectively bypassing the earlier CVE-2026-14257 mitigation. The fix upgrades `brace-expansion` from 1.1.14 to 1.1.18 in `frontend/package-lock.json`, closing the bypass and restoring safe memory bounds during pattern expansion.

high

How Quadratic CPU Consumption happens in JavaScript YAML parsing and how to fix it

A high-severity denial-of-service vulnerability (GHSA-5p4m-2wfm-xmqj) was discovered in js-yaml affecting both the 3.x and 4.x branches, where parsing YAML documents containing `!!omap` tags triggers quadratic CPU consumption. The fix upgrades js-yaml from `^4.1.1` to `5.2.0` in the project's GitHub Actions workflow dependencies, closing the attack surface for any untrusted YAML input processed by CI/CD tooling.

critical

How Missing Rate Limiting happens in Express.js and how to fix it

Two public API endpoints in `server.js` — `/api/health` and `/api/contact` — were exposed without any rate limiting middleware, allowing attackers to exhaust server resources or spam an SMTP server with unlimited requests. The fix adds rate limiting to both endpoints, with stricter controls on the resource-intensive `/api/contact` route that triggers email sending operations. This change closes a directly exploitable denial-of-service vector in a production web service.

high

How Denial of Service via Specific Input Sequence happens in JavaScript (marked) and how to fix it

CVE-2026-41680 is a high-severity Denial of Service vulnerability in the marked Markdown parsing library, affecting versions prior to 18.0.2. By supplying a crafted input sequence to the parser, an attacker can cause the application to hang or exhaust resources, making the frontend unavailable. Upgrading marked from 18.0.0 to 18.0.2 in both `package.json` and `package-lock.json` closes the vulnerability without affecting valid Markdown rendering.

high

How Quadratic CPU Consumption happens in JavaScript YAML parsing and how to fix it

A high-severity denial-of-service vulnerability in js-yaml (GHSA-5p4m-2wfm-xmqj) caused quadratic CPU consumption when resolving `!!omap` YAML types in both the 3.x and 4.x branches. The fix upgrades js-yaml from 3.14.2 to 3.15.1 and from 4.1.1 to 4.3.1, eliminating the algorithmic complexity exploit while leaving all valid YAML inputs unaffected.

high

How Denial of Service via Unbounded Data Happens in JavaScript and how to fix it

CVE-2025-58754 is a high-severity Denial of Service vulnerability in the popular axios HTTP client library, caused by the absence of a data size check on incoming response or request payloads. An attacker who can influence the size of data processed by axios could exhaust server memory or CPU, bringing down dependent Node.js applications. The fix upgrades axios from version 1.8.4 to 1.18.0, closing the unbounded data processing path.