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
•Technically reviewed by Anupam Mediratta•Published August 26, 2026•Reviewed 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.


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.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #10

Related Articles

critical

CVE-2026-59873: node-tar 7.5.11 DoS via Crafted Gzip Bomb

node-tar versions 7.5.11 through 7.5.18 are vulnerable to a denial-of-service attack through maliciously crafted gzip archives that decompress to disproportionately large sizes. An attacker can exploit this to exhaust memory and CPU resources by submitting a small, highly compressed archive that expands beyond configured limits during extraction.

high

MapManager.get() Race Condition Duplicates API Requests

The MapManager's `get(mapUid, cache)` method used a check-then-act pattern that permitted multiple concurrent requests to pass the cache miss check simultaneously, triggering redundant API calls and risking cache corruption. The fix introduces a `_pending` promise map to deduplicate in-flight fetches for identical map UIDs.

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.

critical

No Rate Limit on /api/uploads/presign Enables DoS

The `/api/uploads/presign` endpoint accepted unlimited concurrent requests to generate storage presigned URLs, giving an attacker a free lever to exhaust storage-provider quotas and server resources. The fix adds an `express-rate-limit` middleware capping each client to 30 requests per minute on that route.