Securing your pnpm supply chain

April 3, 20262 min read


Supply chain attacks on npm packages are becoming more frequent. The pattern is almost always the same: a package gets compromised, a malicious postinstall script runs on your machine, and sensitive data is exfiltrated before anyone notices. The good news is that pnpm v10 ships with a handful of settings that make this a lot harder.

Since v10, postinstall scripts are disabled by default. You still need to explicitly allow the packages that legitimately need them (native addons, esbuild, etc.) via allowBuilds. Add strictDepBuilds: true to turn missing allowlists into hard CI errors instead of silent warnings.

minimumReleaseAge delays installs of freshly published versions. Most compromised packages are detected and unpublished within hours, so even a 24-hour delay covers you well. blockExoticSubdeps prevents transitive dependencies from pulling code directly from GitHub repos or raw tarball URLs. And trustPolicy: no-downgrade aborts installs when a package suddenly loses its provenance or signatures, which is often a sign of account compromise.

Putting it together

Here are two configs depending on how strict you want to be.

Strict config

For teams that want the highest security guarantee. Every postinstall script must be explicitly approved, installs fail loudly on anything suspicious, and you wait a week before pulling in new package versions.

# pnpm-workspace.yaml
 
strictDepBuilds: true
blockExoticSubdeps: true
trustPolicy: no-downgrade
trustPolicyIgnoreAfter: 43200
 
minimumReleaseAge: 10080 # 1 week
minimumReleaseAgeExclude:
  - typescript
  - '@types/node'
 
allowBuilds:
  esbuild: true
  fsevents: true
  # add your other native deps here

Relaxed config

A more pragmatic setup for smaller projects or teams that don't want to deal with frequent CI failures. Still blocks the most obvious attack vectors without being too noisy.

# pnpm-workspace.yaml
 
blockExoticSubdeps: true
trustPolicy: no-downgrade
 
minimumReleaseAge: 1440 # 1 day
 
allowBuilds:
  esbuild: true
  fsevents: true

A few more things worth doing

  • Use --frozen-lockfile in CI to ensure reproducible installs
  • Commit your pnpm-lock.yaml to version control

Conclusion

Even the relaxed config already covers the most common attack vectors. Start there and tighten it up as needed.