InformationalSupply chainMonitoring

npm 12 turns off dependency install scripts by default, and blocks git and remote-URL dependencies unless you allow them

npm 12 skips dependency install scripts and refuses git and URL dependencies unless allowed. Upgrade, run npm approve-scripts and commit the allowlist.

Published
Updated
Fixed in
npm 12.0.0 (8 July 2026); preview warnings from npm 11.16.0
Exploitation
Not applicable. This is a platform change that blocks the install-time step most npm malware relies on

What happened

GitHub announced the changes on 9 June 2026 and said they were already visible as warnings in npm 11.16.0 and later (GitHub changelog). npm 12.0.0 was published on 8 July 2026 (npm; The Hacker News). New defaults:

  • allowScripts is off. preinstall, install and postinstall scripts from dependencies do not run unless allowed. This includes the implicit node-gyp rebuild npm runs for a package with a binding.gyp and no install script.
  • prepare scripts from git, file and link dependencies are blocked the same way.
  • --allow-git defaults to none. Git dependencies, direct or transitive, are not resolved. GitHub cites a code-execution path where a git dependency’s .npmrc overrides the git executable even with --ignore-scripts.
  • --allow-remote defaults to none. Dependencies from remote URLs, such as https tarballs, are not resolved.
  • --allow-file and --allow-directory keep their old defaults.

Warning or error? Early reports disagreed. The npm 12 documentation settles it for scripts: installs “silently skip lifecycle scripts” for any dependency without a matching allowScripts entry, and end with a list of the packages whose scripts were skipped (npm docs). The install does not fail. A package that needed its script, such as a native addon, will then fail later, at run time.

The same release cycle also cuts what granular access tokens can do. GitHub plans to remove direct publishing from them in January 2027 and move automated publishing to trusted publishing (OIDC) or staged publishing (The Hacker News).

Am I affected?

This change protects you only once npm 12 is the version that actually runs npm install, on laptops and on CI images.

bash
# Which npm is running here (12.x or later has the new defaults)
npm -v

# Dependencies whose install scripts would be (or are being) skipped
npm approve-scripts --allow-scripts-pending

# Packages in the lockfile that declare install scripts
grep -n '"hasInstallScript": true' package-lock.json

# Git and URL dependencies that npm 12 will refuse without --allow-git / --allow-remote
grep -nE '"(resolved|version)": "(git\+|git:|github:|https?://[^"]*\.tgz)' package-lock.json | grep -v 'registry.npmjs.org'

npm approve-scripts needs npm 11.16.0 or later. If you pin an older npm in CI, for example through a Node.js base image or corepack, the old defaults still apply there.

What to do now

  1. Upgrade npm where installs run. CI images and developer machines. npm 12.2.1 is the latest tag as of 2 November 2026 (npm). Its engines field requires Node.js ^22.22.2 || ^24.15.0 || >=26.0.0.
  2. Review pending scripts. Run npm approve-scripts --allow-scripts-pending. For each package, decide whether it truly needs an install step.
  3. Approve narrowly. npm approve-scripts <pkg> writes a version-pinned pkg@version entry by default, so an update re-prompts. Avoid --no-allow-scripts-pin, which allows any future version, and avoid --all (npm docs).
  4. Deny the rest explicitly with npm deny-scripts <pkg>. approve-scripts never overrides a false entry.
  5. Commit package.json so the allowlist applies on every machine and in CI (GitHub changelog).
  6. Replace git and tarball dependencies with registry versions where you can. Where you cannot, pass --allow-git or --allow-remote only in the job that needs it.
  7. For npx and global installs, which have no project package.json, use the allow-scripts config, for example npm config set allow-scripts=canvas,sharp --location=user (npm docs).

Why this matters

Several attacks covered on this site ran from an install hook. The axios hijack used a postinstall script and the Shai-Hulud worm used preinstall. With npm 12 defaults, neither would have run on npm install. It does not help against payloads that run when your code imports the package, and a broad, unpinned allowlist entry gives the protection back. Keep the allowlist short and pinned.

Sources