Why this matters
In 2025, Sonatype identified over 454,600 new malicious open-source packages across major ecosystems, and over 99% of them were on npm. The biggest attacks hit packages like chalk, debug, and nx through stolen credentials and phishing. In March 2026, even axios (100M weekly downloads) was hijacked.
Many of these attacks relied on malicious code that ran during npm install through lifecycle scripts (preinstall/postinstall), though some (like the chalk/debug compromise) injected runtime code instead. Most were detected within hours, but that was enough to cause damage.
This is my note on what to do about it.
Use pnpm
pnpm v10 has unusually strong supply-chain controls. Three settings in pnpm-workspace.yaml would have reduced exposure to many high-profile attacks from 2025-2026:
# Only install packages older than 7 days.# Most malicious packages are caught and removed within hours.minimumReleaseAge: 10080
# Block trust downgrades.# If a package was published through verified CI/CD before,# block versions published with a regular token.trustPolicy: no-downgrade
# Block all lifecycle scripts by default.# Whitelist only the packages that need them.# (pnpm 10.26.0+, replaces deprecated onlyBuiltDependencies)strictDepBuilds: trueallowBuilds:You can exclude your own packages from the age check:
minimumReleaseAgeExclude: - "@myorg/*"References:
- pnpm: Mitigating Supply Chain Attacks
- pnpm: minimumReleaseAge
- pnpm: trustPolicy
- pnpm: onlyBuiltDependencies
Pin exact versions
Add this to .npmrc:
save-exact=truesave-prefix=''In pnpm v10, dependency lifecycle scripts are already blocked unless explicitly allowed via allowBuilds, so ignore-scripts=true is not needed. If you use npm, add ignore-scripts=true here as well.
This prevents surprise updates from semver ranges. Use Renovate or Dependabot for controlled, reviewable dependency updates.
Use frozen lockfiles in CI
Always use frozen lockfiles in CI so your pipeline installs exactly what is in your lockfile:
pnpm install --frozen-lockfileEven if a malicious version is published, your CI will not pull it unless someone explicitly updates the lockfile.
Install Socket Firewall
Socket Firewall is a free tool that blocks known malicious packages at install time. It works as a proxy between your package manager and the registry.
npm i -g sfwMake it permanent with a shell alias:
# Add to .zshrc or .bashrcalias pnpm='sfw pnpm'If you use GitHub, add the Socket for GitHub app. It monitors dependency changes in PRs and analyzes new dependency risk.
References:
Use Docker for installs
Running pnpm install inside Docker limits what a malicious package can access. By default, it cannot reach your SSH keys, cloud credentials, or home directory, but it can still read build context, environment variables, .npmrc tokens, and exfiltrate data over the network.
# Stage 1: install deps in isolationFROM node:22-alpine AS depsWORKDIR /appCOPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./RUN corepack enable && pnpm install --frozen-lockfile
# Stage 2: build with source codeFROM node:22-alpine AS buildWORKDIR /appCOPY --from=deps /app/node_modules ./node_modulesCOPY . .RUN pnpm buildDocker is a containment layer, not a prevention layer. Use it alongside the tools above, not instead of them.
Reduce your attack surface
A 2019 npm ecosystem study found the average package depends on 79 transitive packages from 39 maintainers. Every dependency is a potential risk.
Before adding a new package:
- Check if a native Node.js or Web API can do the same thing
- Check the package on npmx.dev for detailed analysis
- Look for the provenance badge on npmjs.com
- Check maintainer count and recent activity
The es-tooling/module-replacements repo lists npm packages that can be replaced with native alternatives.
If you publish packages
If your project publishes npm packages, you are also a potential target. Both the Nx and Axios compromises happened because attackers got access to publish tokens.
- Use npm Trusted Publishing (OIDC) to publish from CI/CD without long-lived tokens
- Require 2FA on your npm account
- Remove any
NPM_TOKENfrom CI workflows if you use Trusted Publishing (if both are present, npm uses the token, which defeats the purpose) - Prefer OIDC-based release pipelines over manual
npm publish
Other tools
- Aikido Safe Chain - wraps npm/pnpm/yarn/bun with extra security checks, free and open source
- Snyk - vulnerability scanning with CLI and CI/CD plugins
- StepSecurity - hardens GitHub Actions workflows
pnpm audit- built-in vulnerability scanning, useful but does not detect malware without a CVE
Quick reference
minimumReleaseAge: 10080trustPolicy: no-downgradestrictDepBuilds: trueallowBuilds:save-exact=truesave-prefix=''# Install Socket Firewallnpm i -g sfw
# Use itsfw pnpm install --frozen-lockfile