npm v12 Stops Running Install Scripts by Default in July. That Breaks Real Packages, Not Just Malware — Here's Your Audit List.
On June 9, GitHub posted the breaking changes for npm v12, and one line matters more than the rest: allowScripts will be off by default. When v12 lands in July, the lifecycle scripts that have run automatically on every npm install for fifteen years (preinstall, install, postinstall) won't run for your dependencies unless you explicitly approve them. The behavior is already available as opt-in warnings in npm 11.16.0 and later, so you can see exactly what breaks before the default flips.
This is a good security decision. It's also going to ruin somebody's Saturday, and it might be yours, because the change doesn't only block malware. It blocks the legitimate install scripts a real chunk of the ecosystem quietly relies on.
What's actually changing
Three defaults flip. allowScripts goes off, so dependency lifecycle scripts don't execute without approval. --allow-git=none and --allow-remote=none become the baseline, tightening what npm will pull and run during an install.
The reasoning is the entire supply-chain story of the past two years. The fastest way to compromise a developer machine has been a malicious postinstall script that fires the instant you run npm install: no code imported, no function called, just the act of installing. The Shai-Hulud-style worms, the typosquat campaigns, the Red Hat namespace compromise: a lot of them weaponized exactly this. Turning lifecycle scripts off by default removes the single most reliable execution trigger in the ecosystem. Hard to argue with the intent.
The catch that bites real projects
Here's the part the security headlines skip. npm runs an implicit node-gyp rebuild for native modules: a package with a binding.gyp file and no explicit install script still gets a build step, because npm infers one. Under v12's default, that implicit rebuild is blocked too.
So this isn't only "untrusted packages can't run scripts." It's "your native dependency that compiles a C++ addon on install silently fails to build." Anything in your tree that leans on node-gyp (and you'd be surprised how much transitively does) can stop working after an upgrade you thought was routine. The failure won't necessarily be loud. You'll get a module that didn't compile and an error three layers down that doesn't say "I blocked your install script."
The publishing side tightens too
If you publish packages, v12 isn't just an install-time change. Local publishing will require two-factor authentication. Granular access tokens get a maximum lifetime of seven days, so the long-lived token you pasted into a CI secret two years ago and forgot about isn't a viable pattern anymore. And trusted publishing leans on OIDC workflows and provenance attestations: your package proves it was built where it claims to have been built.
For a solo operator with a couple of small packages on npm, the seven-day token cap is the one that'll actually change your habits. The "set it and forget it" publish token is dead. You move to short-lived tokens or OIDC-based trusted publishing from CI, full stop.
What I'd audit this weekend
Don't wait for July to find out which of your projects break. Upgrade to npm 11.16.0 or later in a branch, turn on the warnings, and run a clean install.
Walk your dependency tree for native modules: anything with a binding.gyp or that compiles on install (the usual suspects: image processing, crypto, database drivers, anything wrapping a C library). Those are your highest-risk breakages. Then check your own published packages: if any of them does real work in a postinstall (building a binary, downloading a platform-specific asset, running a setup step), your users are about to hit a wall, and you want to either remove that dependency on lifecycle scripts or document the approval flow loudly. Finally, look at your CI. A pipeline that runs npm ci and assumes scripts execute will behave differently under v12, and you'd rather discover that in a test branch than in a deploy.
The honest take
I think GitHub made the right call and made it the only way it could be made: as a default, not an opt-in. Security features nobody turns on don't protect anyone, and the npm ecosystem has spent two years proving that the install-script execution model was indefensible. Flipping the default is the only intervention that actually moves the median developer.
But "right call" and "free" are different words. The cost lands on the builders running native dependencies, and it lands as a confusing build failure rather than a clear security message. If you maintain anything with a compile step, the work is on you now: either to make your package survive scripts-off, or to tell your users exactly which approval to grant. The people who read the changelog in June will spend twenty minutes on this. The people who find out in July, mid-deploy, will spend a lot more. Be in the first group.
Author
Lukas
@lukcombinator