← All posts

npm supply chain attacks: hardening installs at project level

ignore-scripts, npm ci, provenance, and lockfile review—layered defenses when node_modules holds thousands of transitive packages.

npm supply chain attacks: hardening installs at project level
Contents

In brief

Headlines about hijacked npm packages keep returning, while “be careful what you install” does not scale to 1,200+ transitive dependencies. A Dev.to post maps the real threat model and five practical defense layers—without pretending npm can be perfectly safe.

What happened

package.json lists dozens of direct deps; node_modules holds hundreds or thousands. Each package can:

  • run code at install time (preinstall / postinstall);
  • be compromised after maintainer phishing;
  • be typosquatted and pasted into a Dockerfile at 2am.

That runs before tests and linters—the moment you npm install.

Why it matters

npm cannot be made safe by default: the trust model is “run strangers’ code.” The gap between default installs and a hardened setup is still large.

Measure Effect
ignore-scripts=true in .npmrc Cuts the main payload delivery path
npm ci --ignore-scripts in CI No lockfile drift
Review lockfile diffs Surfaces new transitive packages
Provenance (Sigstore) Ties builds to repo and workflow
Exact pins + proxy (Verdaccio) + SBOM Fewer surprises, faster incident triage

In practice

  1. Today: set ignore-scripts=true, then npm rebuild only trusted native deps (sharp, better-sqlite3).
  2. Use npm ci only in CI—not npm install.
  3. On dependency PRs, read package-lock.json, not just package.json.
  4. For critical services, exact-pin key dependencies (drop ^ / ~).
  5. Keep secrets out of build environments that ever run install scripts.

Highest ROI single change: disable install scripts by default.

Takeaway

You cannot stop malicious publishes on the registry, but you can stop them from executing in your build environment. npm defaults are weak; your project does not have to inherit them.