npm v12 ships in July with three breaking changes that will silently snap your CI pipelines if you don’t prepare now. GitHub posted the official changelog on June 9: install scripts are off by default, git dependencies are blocked, and remote URL dependencies are blocked. The Hacker News thread hit 178 points fast, and the consensus was blunt — this is overdue, pnpm has done it for 18 months already, and the Miasma worm taking down 73 Microsoft Azure repos in 105 seconds last week is what finally forced the change.
npm v12 Breaking Changes: Scripts Off, Including node-gyp
The most immediately disruptive npm v12 breaking change is the allowScripts default flipping to off. In npm v12, npm install will no longer automatically run preinstall, install, postinstall, or prepare scripts from any dependency. That includes the implicit node-gyp rebuild call that native addon packages depend on to compile their C++ code at install time.
If your project uses sharp, bcrypt, canvas, sqlite3, fsevents, or bufferutil, those packages will fail silently in v12 unless they appear in an allowScripts allowlist committed to package.json. npm 11.16.0 already ships the tooling in advisory mode — scripts still run, but the install summary flags anything unreviewed. In v12, that advisory becomes a hard block.
The allowScripts field in package.json looks like this:
{
"allowScripts": {
"esbuild@0.21.5": true,
"sharp@0.33.5": true,
"node-gyp": true
}
}
Entries are version-pinned by default. That matters: approving esbuild@0.21.5 doesn’t silently extend to esbuild@0.22.0. When a package bumps a version, the approval needs a manual review — which is exactly the point. The allowlist in package.json becomes an auditable artifact, reviewable in pull requests, tracked in source control. Your security team can finally see exactly which dependencies run code at install time.
Why Now: Phantom Gyp Closed the “Ignore Scripts” Loophole
The timing isn’t coincidental. The Phantom Gyp attack on June 3 exploited exactly the behavior npm v12 is blocking. Attackers placed a 157-byte binding.gyp file inside compromised packages. npm saw the file and automatically triggered node-gyp rebuild — a behavior designed for native addons, with no lifecycle script required. Most security scanners don’t monitor it. The payload harvested credentials across npm, GitHub, AWS, GCP, Azure, and Kubernetes, then self-propagated by republishing from compromised maintainer accounts.
That wave compromised 57 packages including @vapi-ai/server-sdk with 408,000 monthly downloads. Two days later, the same worm family used a compromised contributor account to push a malicious commit to Microsoft’s repositories, triggering an automated shutdown of 73 Azure GitHub repos in 105 seconds. npm v12’s allowScripts hard block catches binding.gyp-triggered builds directly — when all install scripts are blocked by default, a malicious binding.gyp file does nothing.
Two More npm v12 Breaking Changes You Might Miss
Beyond scripts, two additional npm v12 breaking changes will catch teams by surprise. Git dependencies — anything using "dep": "git+https://github.com/org/repo.git" in package.json — require an explicit --allow-git flag. The default is none. This closes a separate attack path: an attacker-controlled .npmrc inside a git dependency could previously override the git executable path even when --ignore-scripts was set. Remote URL dependencies ("dep": "https://example.com/package.tgz") follow the same pattern with --allow-remote.
If your team relies on internal HTTPS tarballs for private packages, or if your monorepo pins internal packages to git branches rather than a proper registry, you need to resolve that before July. The right fix is migrating to a registry — GitHub Packages, Nexus, Artifactory — not adding --allow-remote to every CI script.
How to Prepare Now Using npm approve-scripts
npm 11.16.0+ ships everything you need. Upgrade now to get the advisory warnings before v12 enforces them as hard blocks. Then run the approval workflow:
# Step 1: Upgrade npm (advisory mode, no breakage yet)
npm install -g npm@latest
# Step 2: See what would be blocked (read-only, safe to run)
npm approve-scripts --allow-scripts-pending
# Step 3: Approve specific trusted packages
npm approve-scripts sharp esbuild
# Step 4: Commit the allowlist to source control
git add package.json
git commit -m "chore: add allowScripts for npm v12 compatibility"
Skip npm approve-scripts --all. It approves everything indiscriminately and defeats the purpose of the allowlist. Approve packages you’ve reviewed. Let the version-pinning do its job when dependencies update. For CI pipelines, note that npm approve-scripts doesn’t work for global installs — the allowlist lives in a project’s package.json, so it must be committed to source control to take effect in CI.
Related: npm’s Phantom Gyp Worm Proves Signed Packages Aren’t Safe
Is This Actually a Fix?
The Hacker News thread included the inevitable skeptic: “Doesn’t this just change the compromise window from first installation to first run?” That’s a fair question. npm v12 doesn’t make malicious packages harmless — it makes malicious packages harder to execute automatically. A compromised package can still run bad code when you call its functions at runtime. The attack surface shrinks; it doesn’t disappear.
However, the allowlist-as-source-control-artifact is a real improvement. When allowScripts is committed to package.json, your security team can review it in PRs, see exactly which packages run code at install time, and catch version bumps that require re-approval. That’s a meaningful increase in visibility over the current state, where everything runs silently by default. In contrast, the approach pnpm pioneered 18 months ago has now arrived for the larger npm ecosystem — imperfect, but finally here.
Key Takeaways
- npm v12 ships in July; install scripts, git deps, and remote URL deps are blocked by default
- Upgrade to npm 11.16.0 now and run
npm approve-scripts --allow-scripts-pendingto audit your exposure before the hard block lands - Commit the
allowScriptsfield to source control — version-pinned, reviewable in PRs, and required for CI to pass after v12 - If you use internal HTTPS tarballs or git-sourced dependencies, migrate to a proper registry; don’t paper over it with
--allow-remoteflags - npm v12 closes the Phantom Gyp vector directly — a meaningful reduction in attack surface, not a complete solution













