Why I stopped trusting `npm install` the way I used to
The first time I really looked at what happens when I type npm install, I stopped sleeping well for a week.
A package can declare a postinstall script in its package.json. That script runs on your machine, with your user, the moment the install finishes. It can read your filesystem. It can hit the network. It can drop a persistence hook and be gone before you notice. And it doesn’t just run for the packages you asked for — it runs for every transitive dependency in your tree.
The event-stream incident in 2018 is the canonical example. A malicious maintainer took over a legitimate package, published a version that pulled in a payload targeting a specific downstream project, and stole cryptocurrency wallets. Users who ran npm install on any project that transitively depended on event-stream ran the payload.
What I do now
I don’t stop using npm — that would be silly. But I’ve changed a few defaults:
npm install --ignore-scriptsfor anything I don’t fully trust- Look at
package-lock.jsondiffs when they change, not just skim past them - Prefer
npm ciovernpm installin CI so the lockfile is authoritative - Watch dependency counts. Adding a package that pulls in 200 others is a decision I make on purpose now, not by accident
None of this is bulletproof. It’s just less naive than the way I used to work.