npm v12 Made Installs Safer. Check Your Build.
npm v12 makes install scripts opt-in. Learn what changed, which builds may break, and how small teams can update safely.
Most developers have typed npm install so often that it feels harmless. A dependency goes into package.json, a lockfile changes, the app runs, and work continues. But an install can execute code before anyone has opened the package's source. That makes the dependency install step part of a software project's security boundary.
This week, npm v12 made that boundary more visible. According to the npm security changelog, lifecycle scripts such as preinstall, install, and postinstall now default to off unless explicitly allowed. Implicit node-gyp builds are included. It is a breaking change in the right direction: code should not run during installation merely because it was hidden inside a dependency's setup process.
Why this became urgent
Software supply-chain attacks spread fast because one compromised maintainer account or build credential can reach hundreds of downstream projects. GitHub's July update on npm and Actions security describes the pattern clearly: attackers steal credentials, publish malware, and use install-time execution to steal more credentials before teams have time to react.
The new default does not make every JavaScript project safe. It does make one formerly automatic path explicit. If a package genuinely needs a script to compile a native module or generate an asset, the team can approve it deliberately. If it does not, there is no reason to grant it that privilege by accident.
The practical impact is not "never use packages"
There is no prize for rebuilding a date formatter from scratch. Open source is how modern products move quickly. The goal is to make trust proportional to risk.
For a small team, that means a few habits are more valuable than a huge security policy:
- Keep the lockfile in version control so installs are repeatable.
- Read the release notes for a dependency that touches authentication, payments, uploads, infrastructure, or build tooling.
- Add packages for a real need, not because a short helper function looked inconvenient to write.
- Review scripts and dependency changes in pull requests with the same attention as application code.
- Separate credentials used by automated builds from credentials that can publish packages or alter production.
GitHub is also moving toward staged publishing, where a publish needs a human approval step, and has added publish-time malware scanning. Those protections are useful, but they do not replace a team's own review. Security controls reduce the blast radius; they do not turn unreviewed code into trusted code.
The business consequence is reliability
It is easy to describe dependency hygiene as something only developers care about. In practice, it is a customer experience issue. A compromised package can expose credentials, interrupt a launch, or force a rushed rebuild at the exact moment a business needs its website or app to work.
That is why a useful client application should be designed to be maintainable after the launch. At Legacies, our work on websites and custom tools includes the unglamorous parts: clear dependencies, predictable builds, and an update path a future developer can understand. A slick interface does not help much if every routine update feels dangerous.
What to do this week
First, find out which version of npm your builds and local machines actually use. If you move to v12, do not wait for a production deploy to discover that a dependency relies on an install script. Run the build in a controlled environment, identify the scripts that are genuinely necessary, and approve only those.
Second, review tokens. A long-lived token that can both run in CI and publish a public package is a high-value target. The direction of travel is clear: use trusted publishing or staged publishing, require human approval for sensitive changes, and make revocation straightforward if something goes wrong.
The headline is not that npm became inconvenient. The headline is that the old default was too trusting. Good software is often just a collection of sensible defaults, applied before an incident forces the conversation.