Malicious package versions and install scripts are the most common way attackers reach developer machines and CI.
Real attacks on the npm ecosystem follow a few patterns: typosquatting (expresss), compromised maintainer accounts publishing malicious versions of popular packages, dependency confusion (a public package with the name of your private one), and install scripts that steal tokens the moment you run npm install.
Defences built into npm:
- Install script policy. The
allowScriptsfield inpackage.jsonlists which dependencies may runpreinstall/install/postinstall. Manage it withnpm approve-scriptsandnpm deny-scripts. In npm 11 it is advisory (installs report unreviewed scripts); npm 12 blocks unreviewed dependency install scripts by default.--ignore-scriptsdisables them entirely. - Git and URL dependencies:
allow-gitandallow-remotelimit them; npm 12 defaults both tonone. - Cooling-off period:
min-release-age=3(days) avoids versions published minutes ago, the window in which most malicious releases are caught and removed. - Scoped private packages routed to your registry prevent dependency confusion.
npm ciwith a reviewed lockfile,npm audit signatures, and provenance checks.
Around npm: run CI installs with no secrets in the environment, give publish jobs separate minimal permissions, use trusted publishing, and consider package firewalls or scanners (Socket, Snyk, GitHub dependency review) that flag suspicious new versions.
Example
{
"name": "shop-api",
"private": true,
"allowScripts": {
"esbuild@0.25.10": true,
"sharp": true,
"some-telemetry-lib": false
}
}
// Shell:
// npm approve-scripts --allow-scripts-pending # list unreviewed install scripts
// npm approve-scripts esbuild # pin approval to installed version
// npm deny-scripts some-telemetry-lib # never run its scripts
//
// .npmrc:
// min-release-age=3
// allow-git=none
// allow-remote=noneRemember
- Attacks: typosquats, hijacked maintainers, dependency confusion, install scripts
allowScripts+ approve/deny-scripts control install scripts (enforced in npm 12)- Restrict git/URL deps and wait out fresh releases with min-release-age
- Keep secrets out of CI install steps
Watch out for
- Running
npm installin CI jobs that also hold deploy credentials in environment variables.