Back to Blog
high SEVERITY6 min read

How pnpm Trust Policy Misconfiguration happens in Node.js and how to fix it

A missing `trustPolicy` setting in `pnpm-workspace.yaml` left a Node.js application vulnerable to security policy downgrade attacks, where a malicious or compromised package could strip away hardened security configurations. Adding `trustPolicy: no-downgrade` and `blockExoticSubdeps: true` closes this attack vector by ensuring package updates can never weaken existing security settings.

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

Answer Summary

A missing `trustPolicy` configuration in `pnpm-workspace.yaml` (CWE-693: Protection Mechanism Failure) allows malicious or compromised npm packages to downgrade the application's pnpm security settings during installation. The fix is to add `trustPolicy: no-downgrade` to `pnpm-workspace.yaml`, which prevents any package from reducing the trust level below the current policy. Introduced in pnpm v10.21.0, this setting combined with `blockExoticSubdeps: true` closes a supply-chain attack primitive that could be chained with other weaknesses by automated exploit tooling.

Vulnerability at a Glance

cweCWE-693
fixAdded `trustPolicy: no-downgrade` and `blockExoticSubdeps: true` to `pnpm-workspace.yaml`
riskMalicious packages can downgrade pnpm security settings during installation
languageJavaScript/Node.js
root cause`pnpm-workspace.yaml` lacked a `trustPolicy` directive, leaving security settings unprotected against modification by installed packages
vulnerabilitypnpm Trust Policy Misconfiguration

How pnpm Trust Policy Misconfiguration Happens in Node.js and How to Fix It

The Incident

In a Node.js workspace using pnpm, a routine security scan flagged pnpm-workspace.yaml at line 1: the file was missing a trustPolicy directive entirely. While the workspace had several other hardening settings in place — including minimumReleaseAge: 10080 (a 7-day release quarantine), optimisticRepeatInstall: false, and minimumReleaseAgeStrict: true — the absence of trustPolicy left a meaningful gap. Any package installed into this workspace could, in theory, downgrade those carefully configured security settings. This post explains exactly how that happens, why it matters, and what the two-line fix looks like.


The Vulnerability Explained

What trustPolicy Controls

pnpm's trustPolicy setting, introduced in v10.21.0, governs whether packages installed into a workspace are permitted to modify the workspace's own security configuration. Without it, there is no enforcement boundary: a malicious or compromised package could include configuration that weakens the workspace's security posture — for example, relaxing the minimumReleaseAge quarantine or disabling strict checks — and pnpm would have no instruction to reject that downgrade.

The Vulnerable Configuration

Before the fix, pnpm-workspace.yaml looked like this:

# pnpm-workspace.yaml (vulnerable)
optimisticRepeatInstall: false
minimumReleaseAge: 10080
minimumReleaseAgeIgnoreMissingTime: false
minimumReleaseAgeStrict: true
# ← No trustPolicy directive

The file had meaningful protections: minimumReleaseAge: 10080 enforces a 7-day hold on newly published packages (a strong supply-chain defense), and minimumReleaseAgeStrict: true makes that check non-negotiable for known packages. But none of those settings are self-protecting. There is nothing in this configuration that says "a package cannot instruct pnpm to weaken these rules."

How This Could Be Exploited

Consider a supply-chain attack scenario specific to this workspace:

  1. A package in the dependency tree is compromised — either through a maintainer account takeover or a malicious transitive dependency.
  2. The compromised package ships a configuration payload that attempts to reduce minimumReleaseAge or disable minimumReleaseAgeStrict, effectively nullifying the 7-day quarantine that was protecting this workspace.
  3. Without trustPolicy: no-downgrade, pnpm has no policy-level instruction to reject that configuration change.
  4. On the next pnpm install, the weakened settings take effect, and subsequent installs no longer enforce the release age quarantine — opening the door to fast-moving supply-chain attacks that the quarantine was specifically designed to block.

This is an exploit primitive: not independently exploitable in isolation today, but a meaningful building block for automated exploit-development tooling that chains weaknesses together.


The Fix

The pull request added exactly two lines to pnpm-workspace.yaml:

--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -6,3 +6,5 @@ optimisticRepeatInstall: false
  minimumReleaseAge: 10080
  minimumReleaseAgeIgnoreMissingTime: false
  minimumReleaseAgeStrict: true
+trustPolicy: no-downgrade
+blockExoticSubdeps: true

After the Fix

# pnpm-workspace.yaml (hardened)
optimisticRepeatInstall: false
minimumReleaseAge: 10080
minimumReleaseAgeIgnoreMissingTime: false
minimumReleaseAgeStrict: true
trustPolicy: no-downgrade
blockExoticSubdeps: true

What Each Line Does

trustPolicy: no-downgrade

This is the primary fix. The no-downgrade value instructs pnpm to reject any package-level configuration change that would reduce the current security trust level. Concretely:
- The minimumReleaseAge: 10080 quarantine cannot be shortened by a package.
- minimumReleaseAgeStrict: true cannot be set to false by a package.
- No installed package can weaken the workspace's existing hardening settings.

The no-downgrade policy is the most broadly protective option without being so restrictive that it breaks legitimate package behavior. It is the value recommended by the pnpm documentation for production workspaces.

blockExoticSubdeps: true

This companion setting blocks installation of subdependencies that use non-standard or "exotic" resolution protocols — a common vector in supply-chain attacks where a malicious package pulls in dependencies from unusual sources (e.g., git URLs, private registries, or custom protocols) that bypass normal vetting. Combined with trustPolicy: no-downgrade, this closes a second path by which a compromised package could introduce untrusted code.

Together, these two settings make the existing hardening configuration — the 7-day quarantine, the strict release age enforcement — self-protecting and harder to circumvent from within the dependency tree.


Prevention & Best Practices

Always Pair Security Settings with trustPolicy

If your pnpm-workspace.yaml uses any of the following settings, you should also set trustPolicy: no-downgrade to ensure those settings cannot be weakened by installed packages:

  • minimumReleaseAge
  • minimumReleaseAgeStrict
  • auditLevel
  • Any custom security-related workspace configuration

Upgrade to pnpm v10.21.0 or Later

trustPolicy was added in pnpm v10.21.0. If you are running an older version, upgrade first:

npm install -g pnpm@latest
# or
corepack use pnpm@latest

Use Semgrep to Detect Missing Trust Policies

The Semgrep rule package_managers.pnpm.pnpm-trust-policy.pnpm-trust-policy detects both missing and incorrect trustPolicy values in pnpm-workspace.yaml. Add it to your CI pipeline:

# .github/workflows/semgrep.yml
- name: Run Semgrep
  uses: semgrep/semgrep-action@v1
  with:
    config: >-
      p/security-audit
      r/package_managers.pnpm.pnpm-trust-policy.pnpm-trust-policy

Enforce Release Age Quarantines Consistently

The existing minimumReleaseAge: 10080 (7 days) in this workspace is an excellent supply-chain defense. The CISA and OpenSSF both recommend holding newly published packages before installation to allow time for the community to detect malicious releases. Make sure this setting is protected by trustPolicy: no-downgrade so it cannot be silently removed.

Relevant Standards

  • CWE-693: Protection Mechanism Failure — the root CWE for this class of vulnerability, covering cases where a security mechanism can be bypassed or disabled.
  • OWASP A06:2021 – Vulnerable and Outdated Components: Supply-chain hardening at the package manager level directly addresses this category.
  • OWASP Software Supply Chain Security: Recommends enforcing integrity and policy controls at every layer of the dependency resolution process.

Key Takeaways

  • pnpm-workspace.yaml security settings are not self-protecting without trustPolicy: no-downgrade — a malicious package can attempt to weaken minimumReleaseAge or minimumReleaseAgeStrict unless this directive is present.
  • The 7-day quarantine (minimumReleaseAge: 10080) in this workspace is only as strong as its protection against modificationtrustPolicy: no-downgrade is what makes it durable.
  • blockExoticSubdeps: true closes a second supply-chain vector by preventing packages from pulling in subdependencies through non-standard resolution protocols.
  • This is an exploit primitive, not just a misconfiguration — automated attack tools can chain this gap with other weaknesses; removing it proactively raises the cost of a successful attack.
  • pnpm v10.21.0+ is required — if you cannot upgrade, trustPolicy is unavailable and alternative controls (lockfile integrity checks, registry mirroring) should be prioritized.

How Orbis AppSec Detected This

  • Source: The pnpm-workspace.yaml configuration file, which is processed by pnpm during every install or update operation and is therefore reachable by any package in the dependency tree.
  • Sink: The absence of a trustPolicy directive at the workspace configuration level, meaning pnpm had no instruction to reject security-downgrading configuration payloads from installed packages.
  • Missing control: No trustPolicy directive was present, leaving the workspace's existing hardening settings (minimumReleaseAge, minimumReleaseAgeStrict) unprotected against modification by packages.
  • CWE: CWE-693 — Protection Mechanism Failure.
  • Fix: Added trustPolicy: no-downgrade and blockExoticSubdeps: true to pnpm-workspace.yaml, ensuring pnpm enforces a no-downgrade policy on all security settings and blocks exotic subdependency resolution.

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 missing directive in pnpm-workspace.yaml was enough to leave a carefully hardened Node.js workspace vulnerable to supply-chain policy downgrade attacks. The workspace had invested in meaningful protections — a 7-day release quarantine, strict enforcement, and conservative install behavior — but without trustPolicy: no-downgrade, those protections had no defense against being silently weakened by a compromised package. The fix is two lines. The protection it provides is significant: it makes the workspace's security configuration durable, self-protecting, and resistant to the kind of automated exploit chaining that increasingly capable attack tooling relies on. If you use pnpm v10.21.0 or later, add trustPolicy: no-downgrade to your pnpm-workspace.yaml today.


References

Frequently Asked Questions

What is a pnpm trust policy misconfiguration?

A pnpm trust policy misconfiguration occurs when `pnpm-workspace.yaml` is missing the `trustPolicy` directive, allowing installed packages to potentially downgrade or override the workspace's security settings.

How do you prevent trust policy downgrade attacks in pnpm?

Set `trustPolicy: no-downgrade` in your `pnpm-workspace.yaml` file. This ensures no package update or installation can reduce the security trust level below what is currently configured. Available since pnpm v10.21.0.

What CWE is pnpm trust policy misconfiguration?

It maps to CWE-693 (Protection Mechanism Failure), which covers cases where a protection mechanism is absent, incomplete, or can be bypassed by an attacker.

Is pinning package versions enough to prevent trust policy downgrade attacks?

No. Version pinning helps prevent unexpected updates but does not stop a compromised package at a pinned version from attempting to modify workspace security settings. `trustPolicy: no-downgrade` is required to block that vector.

Can static analysis detect pnpm trust policy misconfiguration?

Yes. Semgrep with the rule `package_managers.pnpm.pnpm-trust-policy.pnpm-trust-policy` can detect missing or incorrect `trustPolicy` settings in `pnpm-workspace.yaml` automatically.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #33

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.