You’ve seen the headlines. npm 12 is here. Install scripts are opt-in now. Git dependencies? Opt-in. Remote URLs? Also opt-in. The ecosystem is finally getting serious about supply chain security. Pop the champagne.
Except here’s what actually happens next: a developer runs npm install, sees a wall of warnings about disabled scripts, their build breaks, they Google the error, find a Stack Overflow answer that says npm config set ignore-scripts false, paste it in, and move on with their life.
Security defaults are theater when the ecosystem is addicted to the very practices they restrict.
The top comment on the GitHub changelog nailed it, and it deserves more attention than it got: a lot of people rely on these features being enabled and will simply re-enable them to the same effect. So there’s not really more security. The default changed. The behavior didn’t.
Think about what install scripts actually do in the wild. A package needs to compile native bindings. Another needs to download a binary blob for your platform. A third runs a postinstall hook that patches some compatibility layer. These aren’t edge cases — they’re the connective tissue of modern JavaScript development. When you make that opt-in, you’re not asking developers to reconsider their security posture. You’re asking them to choose between security and a working build.
We know what they’ll pick. Every time.
You can’t firewall your way out of a dependency culture that treats arbitrary code execution as a feature, not a bug.
This is the paradox that nobody in the security discourse wants to confront. Make defaults too restrictive, and power users override them — nullifying the protection. Make them too permissive, and you leave the entire ecosystem one compromised package away from disaster. npm 12 chose the restrictive path, which is objectively the better direction. But direction isn’t destination.
The real leverage point isn’t the default setting. It’s the fact that the JavaScript ecosystem has no safe, drop-in alternatives for what install scripts and remote dependencies do. There’s no signed-binary distribution standard that packages can migrate to. There’s no sandboxed execution model that lets postinstall scripts run without full system access. There’s no cultural shift toward declaring build dependencies explicitly instead of smuggling them through lifecycle hooks.
So developers are left with a binary choice: turn it off and break your build, or turn it back on and accept the same risk you had yesterday. That’s not a security improvement. That’s a guilt trip.
The most dangerous security feature is one that makes you feel safe while changing nothing about your actual risk.
Consider the recent npm malware incidents. Malicious packages with install scripts that exfiltrate credentials, coin miners disguised as utility libraries, typosquats that run arbitrary payloads the second you type npm install. These attacks work not because install scripts exist, but because the ecosystem normalizes running untrusted code at install time without any verification, sandboxing, or audit trail. npm 12’s defaults don’t fix that. They just move the checkbox.
What would actually help? Sandboxed install environments where scripts run with constrained permissions. Cryptographic signing of packages with a web-of-trust model. A first-class mechanism for declaring and verifying build-time dependencies separate from runtime ones. Cultural pressure on package maintainers to eliminate install scripts where possible.
None of that is in npm 12.
What’s in npm 12 is a speed bump. And the top comment is the voice of every developer who will drive right over it.
That’s not to say the change is worthless. Defaults matter. They shape the experience for new projects, for developers who don’t have a decade of muscle memory telling them to re-enable everything, for teams that take the warnings seriously and architect around them. Over years, that compounds. But let’s not pretend it’s a solution.
A speed bump still saves lives — but only if you don’t install a ramp right next to it.
The question isn’t whether npm made the right call. They did. The question is whether the ecosystem will meet them halfway, or whether we’ll keep treating supply chain security as someone else’s problem until the next headline forces another band-aid.
So when you upgrade to npm 12 and your build breaks, pause before you paste that config override. Ask yourself what the install script you’re re-enabling actually does. Ask whether you trust the maintainer. Ask whether there’s an alternative package that doesn’t need to run code on your machine just to exist in your node_modules.
That moment of friction — that’s the actual security feature. Not the default. The pause.
Use it.
FAQ
Q: Won't the new defaults at least help new projects?
A: Yes, and that's not nothing. New projects without legacy dependencies benefit most. But the moment they pull in any package with an install script — and most will — they hit the same fork in the road as everyone else.
Q: So what should I actually do when upgrading to npm 12?
A: Don't blindly re-enable everything. Audit which packages need install scripts, check if alternatives exist, and scope your config overrides to specific trusted packages rather than globally disabling the protection.
Q: Is this just security theater then?
A: Not quite — it's a speed bump, not a wall. Speed bumps still work when people don't build ramps around them. The problem is that the ecosystem makes ramp-building the path of least resistance, and npm hasn't addressed that side of the equation.