You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[BUG] A user/global .npmrcallow-scripts setting is forwarded to git-dependency preparation as an env-layer policy and fails the install with EALLOWSCRIPTS #9783
Setting allow-scripts in a user or global .npmrc (which npm's own warning explicitly recommends for global installs) makes any later npm install/npm ci of a project that has a git dependency requiring preparation fail with:
npm error git dep preparation failed
npm error npm error code EALLOWSCRIPTS
npm error npm error --allow-scripts is not allowed in project-scoped installs.
Add the entries to the "allowScripts" field in package.json, or to .npmrc, instead.
The error is self-contradictory from the user's point of view: it says to put the entry in .npmrc, and it is in .npmrc. The root cause is that npm prepares a git dependency by spawning an inner npm install, forwarding the outer config to it as npm_config_* environment variables. The inner install reads allow-scripts from its env layer, which resolveAllowScripts treats as a command-line/env policy and rejects in a project-scoped install, even though the user never passed --allow-scripts and the value originated in a persistent .npmrc.
Environment
npm: reproduced on 11.17.0and12.0.1 (the current release). On npm 12, git dependencies are blocked by default (EALLOWGIT); once opted in with --allow-git=all, the identical EALLOWSCRIPTS failure occurs. The throw logic in lib/utils/resolve-allow-scripts.js is unchanged on main (same line numbers).
node: v26.5.0
OS: Linux (WSL2, Ubuntu)
How the offending setting gets there
This isn't an exotic hand-edit. Installing a global package with an install script prints (npm 11):
npm warn allow-scripts <pkg>@x.y.z (postinstall: node install.cjs)
npm warn allow-scripts Run `npm install -g --allow-scripts=<pkg>` to allow
these scripts once, or `npm config set allow-scripts=<pkg> --location=user`
to allow them for all global installs.
Following the second suggestion writes allow-scripts=<pkg> to the user .npmrc. From that point on, every git-dependency preparation in every project on the machine fails.
Minimal, self-contained reproduction (no network / external repo required)
R=$(mktemp -d); mkdir -p "$R/dep""$R/app"# A git dependency that has a `prepare` script, so npm must run# "git dep preparation" (an inner `npm install`) to build it.cd"$R/dep"
cat > package.json <<'EOF'{ "name": "gitdep", "version": "1.0.0", "scripts": { "prepare": "node -e \"process.exit(0)\"" } }EOF
git init -q && git add -A && git -c user.email=t@t -c user.name=t commit -qm init
# A consumer project that depends on it via git.cd"$R/app"
cat > package.json <<EOF{ "name": "app", "version": "1.0.0", "dependencies": { "gitdep": "git+file://$R/dep" } }EOF# A USER-level .npmrc containing the entry exactly as# `npm config set allow-scripts=... --location=user` would write it.# (--userconfig isolates the repro from the real user .npmrc; writing the# same line to ~/.npmrc behaves identically.)echo"allow-scripts=whatever">"$R/userrc"
npm install --userconfig "$R/userrc" --cache "$R/cache"# cold cache => real git-dep prep# npm 12: add --allow-git=all (git deps are otherwise blocked with EALLOWGIT)
Actual result
npm error code 1
npm error git dep preparation failed
npm error command <NODE>/bin/node <NODE>/lib/node_modules/npm/bin/npm-cli.js \
install --force --cache=<...> --prefer-offline=false --prefer-online=false \
--offline=false --no-progress --no-save --no-audit --include=dev \
--include=peer --include=optional --no-package-lock-only --no-dry-run
npm error npm warn using --force Recommended protections disabled.
npm error npm error code EALLOWSCRIPTS
npm error npm error --allow-scripts is not allowed in project-scoped installs.
Add the entries to the "allowScripts" field in package.json, or to .npmrc, instead.
Expected result
The install completes. An allow-scripts value that lives in a persistent .npmrc is, by definition, not a command-line flag, and the docs describe the user/global .npmrc as a valid home for it in global contexts. It should not be re-interpreted as a forbidden CLI/env policy simply because npm chose to shell out to an inner npm install to prepare a git dependency.
Notes on the trigger
Requires the git dependency to actually undergo preparation; i.e. it has a prepare script (or otherwise must be built from source). A github dependency whose repository already contains its publishable files and has no prepare script (e.g. is-odd) is packed directly, runs no inner install, and does not trip the bug.
Requires a cold git-dep cache, so the preparation actually runs. A warm cache serves the prepared dep and hides the failure, which makes this present intermittently and confusingly (it breaks npm ci on CI or a clean machine while an incremental npm install on a warm cache "works").
Independent of where the setting lives: reproduced identically with the entry in the user.npmrc, the global (etc/npmrc) file, and even the consumer project's own .npmrc. There is therefore no persistent-config location that both silences the global-install script warning and leaves git-dep installs working.
Root cause (source pointers)
lib/utils/resolve-allow-scripts.js throws EALLOWSCRIPTS when a policy is found in the cli/env sources and the install is not global and not skipProjectConfig (the git-dep-prep inner install is a plain npm install, so skipProjectConfig is false).
The inner preparation install inherits the outer process's npm_config_* environment, so a .npmrc-origin allow-scripts arrives in the inner process as an env-layer value and is treated the same as a command-line flag.
Suggested fixes
(Preferred) When spawning the git-dep preparation install, strip or neutralisenpm_config_allow_scripts from the child environment. The preparation install already runs with a deliberately curated flag set (--force --no-save --no-audit ...), so script policy for the inner build could be passed explicitly rather than inherited ambiently. This seems the cleanest fix: the grouping of the cli and env sources in resolveAllowScripts is deliberate per RFC 868 (env vars are meant to be rejected alongside CLI flags in project-scoped installs), so the defect is the ambient env inheritance into the inner install, not the source classification itself.
Alternatively, in resolveAllowScripts, distinguish a value that genuinely came from a command-line flag from one that arrived via npm_config_* env inheritance, and only reject the former in project-scoped installs—though note this would cut against the RFC's stated intent for the env layer.
At minimum, fix the error message: when the value came from .npmrc (directly or via env inheritance), do not tell the user to "add the entries to .npmrc"; that is where it already is, and the advice sends them in a circle.
Related
fix(arborist): apply allowScripts gate to scripts pacote runs at extract #9777 (open) touches the same neighbourhood; applying the allowScripts gate to scripts pacote runs at extract for git/directory deps, but is a distinct defect: that PR is about the gate not being applied to prepare at extract, whereas this issue is about a persistent .npmrc policy being misclassified as a CLI/env policy in the inner preparation install and aborting it.
Workaround (for anyone hitting this)
Do not persist allow-scripts in a user/global .npmrc. Instead pass it only at the moment of the global install that needs it:
npm install -g <pkg> --allow-scripts=<pkg>
This approves the global install's script without leaving a persistent setting that later breaks git-dependency preparation in unrelated projects.
Summary
Setting
allow-scriptsin a user or global.npmrc(which npm's own warning explicitly recommends for global installs) makes any laternpm install/npm ciof a project that has a git dependency requiring preparation fail with:The error is self-contradictory from the user's point of view: it says to put the entry in
.npmrc, and it is in.npmrc. The root cause is that npm prepares a git dependency by spawning an innernpm install, forwarding the outer config to it asnpm_config_*environment variables. The inner install readsallow-scriptsfrom its env layer, whichresolveAllowScriptstreats as a command-line/envpolicy and rejects in a project-scoped install, even though the user never passed--allow-scriptsand the value originated in a persistent.npmrc.Environment
11.17.0and12.0.1(the current release). On npm 12, git dependencies are blocked by default (EALLOWGIT); once opted in with--allow-git=all, the identicalEALLOWSCRIPTSfailure occurs. The throw logic inlib/utils/resolve-allow-scripts.jsis unchanged onmain(same line numbers).v26.5.0How the offending setting gets there
This isn't an exotic hand-edit. Installing a global package with an install script prints (npm 11):
Following the second suggestion writes
allow-scripts=<pkg>to the user.npmrc. From that point on, every git-dependency preparation in every project on the machine fails.Minimal, self-contained reproduction (no network / external repo required)
Actual result
Expected result
The install completes. An
allow-scriptsvalue that lives in a persistent.npmrcis, by definition, not a command-line flag, and the docs describe the user/global.npmrcas a valid home for it in global contexts. It should not be re-interpreted as a forbidden CLI/envpolicy simply because npm chose to shell out to an innernpm installto prepare a git dependency.Notes on the trigger
preparescript (or otherwise must be built from source). A github dependency whose repository already contains its publishable files and has nopreparescript (e.g.is-odd) is packed directly, runs no inner install, and does not trip the bug.npm cion CI or a clean machine while an incrementalnpm installon a warm cache "works")..npmrc, the global (etc/npmrc) file, and even the consumer project's own.npmrc. There is therefore no persistent-config location that both silences the global-install script warning and leaves git-dep installs working.Root cause (source pointers)
lib/utils/resolve-allow-scripts.jsthrowsEALLOWSCRIPTSwhen a policy is found in thecli/envsources and the install is not global and notskipProjectConfig(the git-dep-prep inner install is a plainnpm install, soskipProjectConfigis false).npm_config_*environment, so a.npmrc-originallow-scriptsarrives in the inner process as an env-layer value and is treated the same as a command-line flag.Suggested fixes
npm_config_allow_scriptsfrom the child environment. The preparation install already runs with a deliberately curated flag set (--force --no-save --no-audit ...), so script policy for the inner build could be passed explicitly rather than inherited ambiently. This seems the cleanest fix: the grouping of thecliandenvsources inresolveAllowScriptsis deliberate per RFC 868 (env vars are meant to be rejected alongside CLI flags in project-scoped installs), so the defect is the ambient env inheritance into the inner install, not the source classification itself.resolveAllowScripts, distinguish a value that genuinely came from a command-line flag from one that arrived vianpm_config_*env inheritance, and only reject the former in project-scoped installs—though note this would cut against the RFC's stated intent for theenvlayer..npmrc(directly or via env inheritance), do not tell the user to "add the entries to.npmrc"; that is where it already is, and the advice sends them in a circle.Related
allowScriptsgate to scripts pacote runs at extract for git/directory deps, but is a distinct defect: that PR is about the gate not being applied toprepareat extract, whereas this issue is about a persistent.npmrcpolicy being misclassified as a CLI/env policy in the inner preparation install and aborting it.Workaround (for anyone hitting this)
Do not persist
allow-scriptsin a user/global.npmrc. Instead pass it only at the moment of the global install that needs it:This approves the global install's script without leaving a persistent setting that later breaks git-dependency preparation in unrelated projects.