Back to Blog
high SEVERITY5 min read

How missing pnpm trustPolicy happens in Node.js and how to fix it

The `pnpm-workspace.yaml` file in this Node.js library was missing the `trustPolicy` setting, leaving the workspace without protection against publisher-trust downgrade attacks introduced in pnpm 10.21.0. Adding `trustPolicy: no-downgrade` ensures that once a package's publisher trust evidence is established, a later malicious or compromised release cannot silently weaken it during an install or update.

O
By Orbis AppSec
Published September 7, 2026Reviewed September 7, 2026

Answer Summary

This is a pnpm supply-chain hardening gap (CWE-1357: Reliance on Insufficiently Trustworthy Component) in `pnpm-workspace.yaml`, where the absence of `trustPolicy: no-downgrade` allowed a future package version to downgrade the security/trust evidence pnpm had already recorded for that dependency. The fix adds a single top-level key, `trustPolicy: no-downgrade`, to the workspace config, which pnpm enforces on every install to reject releases that regress trust guarantees.

Vulnerability at a Glance

cweCWE-1357 (Reliance on Insufficiently Trustworthy Component)
fixAdded `trustPolicy: no-downgrade` to `pnpm-workspace.yaml` to lock in trust guarantees across updates
riskMalicious or compromised package updates could downgrade publisher trust settings during install
languageYAML (pnpm workspace configuration) / Node.js tooling
root cause`pnpm-workspace.yaml` had no `trustPolicy` key, so pnpm defaulted to permissive trust handling
vulnerabilityMissing pnpm trustPolicy (trust-downgrade protection)

Introduction

The pnpm-workspace.yaml file is the control center for how pnpm resolves, builds, and trusts every dependency in a Node.js monorepo. In this repository, that file defined the workspace's packages and an allowBuilds list for native modules like @discordjs/opus and esbuild, but it never set a trustPolicy. That's a small omission with an outsized consequence: without an explicit trust policy, pnpm falls back to more permissive behavior when a dependency publishes a new release, which means the trust evidence pnpm has already recorded for a package could quietly be downgraded by a future update.

This matters for any team relying on pnpm-workspace.yaml to manage third-party code, because the workspace config is exactly the kind of file that rarely gets a second look after initial setup — until an automated scanner (in this case, Semgrep) flags it.

The Vulnerability Explained

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

packages:
  - "."

allowBuilds:
  '@discordjs/opus': true
  esbuild: true

There is no trustPolicy key anywhere in the file. Since pnpm 10.21.0, this setting exists specifically to answer one question: if a package publishes a new version, is pnpm allowed to accept trust evidence that is weaker than what it already recorded? Without an explicit no-downgrade policy, the answer defaults to "yes" — pnpm will accept the new release's trust metadata even if it represents a regression.

Concretely, imagine a legitimate maintainer's npm account for a transitive dependency is compromised, or a malicious actor publishes a typosquat-adjacent update that manipulates provenance/trust signals. If the workspace has no trustPolicy: no-downgrade, pnpm has no built-in rule stopping that update from silently lowering the bar the next time pnpm install or pnpm update runs in this repository. The attacker doesn't need to exploit application code directly — they just need to get a downgraded-trust package accepted during a routine dependency bump, at which point it becomes a foothold for further supply-chain compromise (e.g., paired with a malicious postinstall script or a build step enabled via allowBuilds).

In a real-world scenario for this specific repo: the allowBuilds section already grants build permissions to @discordjs/opus and esbuild. If either of those packages' publisher trust were downgraded by a future malicious release, and no trustPolicy guard existed, pnpm would have no additional line of defense — the combination of "trust downgrade allowed" plus "build execution allowed" is exactly the kind of chainable primitive automated exploit tooling looks for.

The Fix

The fix is minimal but precise — a single new top-level key added to pnpm-workspace.yaml:

Before:

packages:
  - "."

allowBuilds:
  '@discordjs/opus': true
  esbuild: true

After:

packages:
  - "."

trustPolicy: no-downgrade

allowBuilds:
  '@discordjs/opus': true
  esbuild: true

By setting trustPolicy: no-downgrade, pnpm now enforces that any dependency update accepted into this workspace cannot regress the publisher trust evidence pnpm previously established for that package. If a future release attempts to weaken that trust signal, pnpm rejects it rather than silently installing it.

The accompanying CHANGELOG.md update makes the intent explicit for downstream consumers:

- Reject dependency releases with downgraded publisher trust evidence while preserving the 48-hour release-age policy. (#8) Thanks @anupamme.

This one-line config change requires no code changes elsewhere in the project because it operates entirely at the package-manager level — it doesn't affect how existing valid packages install or build, it only adds a rejection path for a specific class of malicious update.

Prevention & Best Practices

  • Always set trustPolicy explicitly in pnpm-workspace.yaml rather than relying on defaults. Use no-downgrade unless you have a specific, documented reason not to.
  • Combine trust policy with minimumReleaseAge (referenced in this repo's changelog as the "48-hour release-age policy") to add a time buffer before newly published versions are trusted — this gives the community time to catch and report malicious releases before your CI ever pulls them.
  • Audit allowBuilds regularly. Packages granted build permissions (like @discordjs/opus and esbuild here) can execute arbitrary code during install; pair build allowlists with strict trust enforcement.
  • Run Semgrep or equivalent supply-chain rules in CI so configuration regressions (like a missing trustPolicy) are caught automatically before merge, not discovered after an incident.
  • Keep pnpm current. trustPolicy was only introduced in pnpm 10.21.0 — teams on older versions need to upgrade pnpm itself before this control is even available.
  • Reference OWASP's guidance on Software Supply Chain Security for broader dependency risk management practices.

Key Takeaways

  • pnpm-workspace.yaml had zero trustPolicy configuration, defaulting the workspace to permissive trust handling on every dependency update.
  • The fix adds exactly one line — trustPolicy: no-downgrade — with no application code changes required.
  • This workspace also grants build execution via allowBuilds for @discordjs/opus and esbuild, which raises the stakes of any trust-downgrade path being left open.
  • Trust policy enforcement pairs with release-age policies (noted in the changelog) as complementary, not redundant, supply-chain defenses.
  • This is a config-level control, not an application-level one — it's enforced by pnpm itself on every install/update, making it a low-cost, high-leverage fix.

How Orbis AppSec Detected This

  • Source: Dependency update events processed by pnpm during install/update operations against pnpm-workspace.yaml.
  • Sink: pnpm's dependency trust-resolution logic, which reads workspace configuration to decide whether to accept a package's trust evidence.
  • Missing control: No trustPolicy key was defined, so pnpm had no explicit instruction to reject trust-evidence downgrades on package updates.
  • CWE: CWE-1357 — Reliance on Insufficiently Trustworthy Component.
  • Fix: Added trustPolicy: no-downgrade to pnpm-workspace.yaml, instructing pnpm to reject any dependency release that downgrades previously established publisher trust evidence.

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 missing trustPolicy in pnpm-workspace.yaml is easy to overlook because it's a configuration gap, not a broken function or an injected string. But in a supply-chain context, configuration is the attack surface. This project's fix — adding trustPolicy: no-downgrade alongside its existing allowBuilds permissions — closes off a path where a future malicious or compromised package release could quietly weaken the trust guarantees pnpm had already established, without touching a single line of application logic. Treat your package manager's workspace config with the same scrutiny as your source code: a one-line omission here can be the difference between blocking a supply-chain attack and enabling one.

References

Frequently Asked Questions

What is a missing pnpm trustPolicy vulnerability?

It's a configuration gap where a pnpm workspace does not set `trustPolicy`, meaning pnpm has no explicit rule preventing a package's publisher trust evidence from being weakened by a later, potentially malicious release.

How do you prevent missing trustPolicy issues in pnpm workspaces?

Explicitly set `trustPolicy: no-downgrade` in `pnpm-workspace.yaml` (pnpm ≥10.21.0) and enforce this via CI linting or Semgrep rules so new workspaces don't regress.

What CWE is missing pnpm trustPolicy classified under?

It maps to CWE-1357, Reliance on Insufficiently Trustworthy Component, since the workspace trusts dependency updates without verifying trust evidence hasn't regressed.

Is pinning dependency versions enough to prevent this issue?

No. Version pinning limits which versions are installed but doesn't stop trust metadata from being downgraded when you do intentionally upgrade; `trustPolicy: no-downgrade` is still needed as a dedicated control.

Can static analysis detect missing pnpm trustPolicy?

Yes. Semgrep rules like `package_managers.pnpm.pnpm-trust-policy.pnpm-trust-policy` scan `pnpm-workspace.yaml` for the absence or misconfiguration of the `trustPolicy` key.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #8

Related Articles

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How dependabot-missing-cooldown happens in GitHub Actions/Node.js and how to fix it

The repository's `.github/dependabot.yml` had no cooldown period configured, meaning Dependabot could immediately propose updates to newly published package versions with zero time for the community to flag malware or instability. The fix adds a `cooldown` block with `default-days: 7` to both the `npm` and `github-actions` ecosystems, forcing a 7-day waiting period before new releases are surfaced as update PRs.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.

critical

How Remote Code Execution Happens in Handlebars Template Compilation and How to Fix It

CVE-2026-33937 is a critical remote code execution vulnerability in Handlebars.js that allows attackers to execute arbitrary code by passing maliciously crafted Abstract Syntax Tree (AST) objects to the compile() function. The vulnerability was patched in version 4.7.9, and we've upgraded to protect against this threat vector.

critical

How Denial of Service via Gzip Bomb happens in Node.js and how to fix it

A critical Denial of Service vulnerability (CVE-2026-59873) in the `tar` npm package allowed attackers to craft malicious gzip archives that could exhaust memory or CPU during decompression. The fix upgrades `tar` from 7.5.11 to 7.5.21 across `package.json` and `package-lock.json`, closing the resource-exhaustion path without changing any application code.