Learn / Attack archive / Lesson 21

Poisoned packages — the npm worms

How one phished maintainer turned into hundreds of infected packages, why npm install runs code before you look at it, and the settings that buy you a week of safety.

Last updated: 2026-09-23

What it is

A supply chain attack does not attack your code. It attacks code you pull in from someone else: a package, a build tool, a CI action. When the attacker controls a package you depend on, their code runs on your laptop, your build server and your production server, with your permissions.

The npm ecosystem is the favourite target because of three facts:

Why it is a rule

Why it keeps working

How to do it

1. Install from a lockfile, always

Commit package-lock.json and install with npm ci in CI and on servers. That installs the exact versions you tested, not "whatever is newest".

2. Wait before trusting a new version

ini
# .npmrc
min-release-age=7
ignore-scripts=true

min-release-age refuses packages published in the last seven days. Nearly every poisoned release above was pulled within that window. ignore-scripts stops lifecycle scripts from running; the few packages that truly need a build step can be run by hand or allowed one by one.

3. Keep secrets out of reach of installs

4. Protect the maintainer, if you publish

Use a passkey or security key for npm and GitHub, not a code from an app or SMS. The chalk phish would have failed against a key, because a key refuses to sign in to the wrong domain.

5. Pin CI actions by commit

yaml
- uses: some-org/some-action@8f4b7c2e1d...   # a full commit SHA, not @v4

A tag like @v4 can be moved to malicious code. A commit hash cannot.

6. Keep the list short

Every dependency is a stranger with commit rights to your server. Before adding one, ask whether twenty lines of your own code would do.

How we do it here

Dependencies are pinned by a committed lockfile, and the list is kept deliberately short: the server uses a small set of well-known packages, and features that could be written in a few lines are written in-house. Build and minify steps run before deploy, so the running server does not need build tooling.

Benefits

Disadvantages

Checklist

Sources

Read this lesson as Markdown