npm's next major version flips three install behaviors from automatic to opt-in, closing well-known supply-chain code-execution paths. The changes are already shipping behind warnings in npm 11.16.0, so the migration work can start before the July 2026 release.

The npm team has published the breaking-change list for npm v12, and the headline is straightforward: three things npm install does for you automatically today will require explicit permission after the upgrade. The release is estimated for July 2026, and every one of these changes is already available behind warnings in npm 11.16.0 or newer, so teams can see exactly what will break before anything actually does.
What's claimed
The framing from GitHub is that v12 introduces "security-related default changes" to npm install. In practice that means three separate config defaults flip from permissive to restrictive: lifecycle scripts stop running, Git dependencies stop resolving, and remote URL dependencies stop resolving. Each becomes something you opt into rather than something you opt out of.
What's actually new
The interesting part here is not that npm invented new flags. Most of these controls have existed for a while, --ignore-scripts being the obvious example. What changes is the default. That distinction matters more than it sounds, because supply-chain attacks rely on the gap between what a developer intends to do (download some code) and what npm actually does (download code and then execute parts of it).
allowScripts defaults to off. Today, when you install a package, npm will run its preinstall, install, and postinstall scripts automatically. This is the mechanism behind a long list of real-world malware incidents, where a compromised or typosquatted package runs arbitrary code on your machine the moment it lands in node_modules. In v12 those scripts will not run unless you have explicitly allowed the package.
The detail worth understanding is the native build case. A package that ships a binding.gyp but no explicit install script still gets blocked, because npm runs an implicit node-gyp rebuild for it. So packages with native addons, a meaningful chunk of the ecosystem, will need approval too. The same blocking applies to prepare scripts from git, file, and link dependencies.
The workflow GitHub recommends is to run npm approve-scripts --allow-scripts-pending to list everything that would be blocked, then npm approve-scripts for the packages you trust and npm deny-scripts for the rest. The resulting allowlist gets written into package.json and is meant to be committed, which means the decision about which dependencies are allowed to execute code becomes a reviewable, version-controlled artifact rather than an invisible default. That is the genuinely useful structural shift here.
--allow-git defaults to none. Git dependencies, both direct and transitive, will no longer resolve unless allowed via --allow-git. The reasoning given is specific: a Git dependency's .npmrc could override the Git executable, producing code execution even when you passed --ignore-scripts. In other words, turning off scripts was not actually enough to neutralize a malicious Git dependency, which is a good illustration of why piecemeal hardening leaves gaps. This one was announced back on 2026-02-18 and is available in npm 11.10.0+.
--allow-remote defaults to none. Dependencies pulled from remote URLs, such as HTTPS tarballs, direct or transitive, will no longer resolve unless allowed via --allow-remote. This flag landed in npm 11.15.0+. The related --allow-file and --allow-directory flags are explicitly not changing their defaults in v12, so local file and directory dependencies keep working as before.
Limitations and the practical cost
None of this is free for existing projects, and the npm team is reasonably upfront about that. If your install routine depends on lifecycle scripts, and many do for things like compiling native modules, fetching binaries, or running build steps, those will stop the moment you upgrade unless you have built your allowlist first. The migration is not automatic; npm can show you the warnings, but a human has to decide which packages are trustworthy enough to execute code.
There is also a judgment problem baked into the approval step. npm approve-scripts tells you which packages want to run scripts, but it cannot tell you whether those scripts are benign. A developer rubber-stamping the entire pending list to make the warnings go away ends up roughly where they started, just with extra steps. The security benefit is real only if the approval is treated as an actual review, and at scale that review is tedious. The saving grace is that the allowlist lives in package.json and goes through code review like any other change, so at least a second person can see what was approved.
For CI and tooling, expect breakage in scripts that assume Git or remote dependencies resolve silently. Transitive cases are the ones that will surprise people, since a top-level dependency you trust might itself pull a Git or remote dependency several layers down, and that now needs an explicit allow flag too.
The broader pattern
This fits a direction the whole ecosystem has been moving for a few years: treating installation as an untrusted operation by default. Package managers in other languages have grappled with the same lifecycle-script problem, and the consensus has slowly shifted toward making code execution during install an explicit choice rather than an implicit one. npm flipping these defaults is the largest single move in that direction for the JavaScript ecosystem, simply because of how many projects it touches.
The migration path is sensible. Upgrade to npm 11.16.0 or later, run your normal install, and read the warnings. Use npm approve-scripts --allow-scripts-pending to see which packages have scripts, approve the ones you trust, and commit the updated package.json. After the v12 upgrade, only the scripts you approved keep running, and anything left unapproved stops. Full documentation covers npm approve-scripts, npm deny-scripts, and the allow-scripts config for npx and global installs, and GitHub has opened a community discussion for questions.
The time to do this work is now, while the changes are warnings rather than errors. A project that builds its allowlist against 11.16.0 over the next month will upgrade to v12 in July without anything breaking. A project that ignores the warnings until v12 ships will spend that day figuring out why its installs suddenly fail.

Comments
Please log in or register to join the discussion