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] npm exec / npx forwards persistent user-level allow-scripts to children as npm_config_allow_scripts, failing project-scoped installs in the child (EALLOWSCRIPTS) #9968
Setting allow-scripts in a user .npmrc (which npm's own warning recommends for global installs, and which is a valid config source for project installs) makes any tool launched via npx/npm exec that shells out to a project-scoped npm install fail with:
npm error code EALLOWSCRIPTS
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.
npm exec exports the resolved npm config into the child process's environment as npm_config_* variables. Because the outer process read allow-scripts from a user .npmrc, the launched tool (and anything it spawns) inherits npm_config_allow_scripts, and when it reaches an inner project-scoped npm install, that inner npm resolves the value via its env source — which resolveAllowScripts groups with cli and rejects for non-global installs. The user never passed --allow-scripts; the value lives exactly where the error message tells them to put it.
This is the npm exec sibling of #9783 (git-dependency preparation) and #9912/#9913 (npm run-script lifecycle export). The #9913 fix keeps persistent allow-scripts out of lifecycle-exported config; the npm exec child env export still forwards it (verified on 12.0.2 below).
Environment
npm: 11.17.0 (full repro) and 12.0.2 (exec forwarding and EALLOWSCRIPTS both independently verified)
node: v24.19.0
OS: Windows 11 (Git Bash); the config/export mechanics are platform-independent
How the offending setting gets there
Same as #9783 / #9912 — the documented workflow. Installing a global package with an install script prints:
npm warn allow-scripts <pkg>@x.y.z (postinstall: node install.js)
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 then on, every npx-launched tool that performs project-scoped npm installs fails.
Minimal, self-contained reproduction
Isolated --userconfig so the reporter's own .npmrc is not involved:
R=$(mktemp -d)echo"allow-scripts=whatever">"$R/userrc"# exactly as `npm config set allow-scripts=... --location=user` writes it
mkdir "$R/app"&&cd"$R/app"echo'{"name":"app","private":true}'> package.json
# (A) Direct project-scoped install with the same user config — works
npm install is-even --userconfig "$R/userrc"# (B) Same install reached through npx — fails
npx -y --userconfig "$R/userrc" -c 'npm install is-even'
Actual result (B)
npm error code EALLOWSCRIPTS
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.
On npm 12.0.2: npm exec still sets npm_config_allow_scripts in the child environment, and an inner install with that variable present fails with the same EALLOWSCRIPTS error.
Real-world impact
npx @robzolkos/lazypi — a community installer for the Pi coding agent that shells out to pi install, which runs npm install <pkg> --prefix <pi-dir> --legacy-peer-deps for each package — fails on all 23 npm-backed packages at once with this error on any machine whose user .npmrc carries the recommended allow-scripts entry. The same applies to any scaffolder/bootstrap tool driven via npx that runs nested project-scoped npm installs. Notably, running the identical installer from a global install (plain Node child, no npm exec env) works fine, which makes this particularly confusing to debug.
Expected result
The npx-launched tool's inner install completes. A persistent user-level allow-scripts policy is not a command-line flag; npm exec should not convert it into one by exporting it into the child environment.
Root cause (source pointers)
lib/utils/resolve-allow-scripts.js — policyFromSources(npm, ['cli', 'env']) groups the env source with cli; a non-global, non-skipProjectConfig install throws EALLOWSCRIPTS when that layer has a policy.
npm exec exports resolved config (including user .npmrc values such as allow-scripts) to the child process as npm_config_*. fix(config): avoid exporting persistent allow-scripts #9913 excluded allow-scripts from lifecycle exports; the exec path's export still includes it.
Suggested fixes
(Preferred) Apply the fix(config): avoid exporting persistent allow-scripts #9913 treatment to the npm exec child environment: keep persistent allow-scripts policy out of exec-exported config, so nested npm commands reload it from its original config source instead of treating it as an environment override.
Alternatively, strip npm_config_allow_scripts from the child env in npm exec — it is a one-off/global-context flag by design, so there is no valid exec-child use for it.
At minimum, fix the error message for the env-inherited case: telling the user to "add the entries to .npmrc" sends them in a circle — the entry already is in .npmrc.
Tools/launchers: don't reach the tool through npm exec (a globally installed copy runs with a clean environment and works). End users: keep allow-scripts out of persistent user config and pass it per-invocation for global installs only (npm install -g <pkg> --allow-scripts=<pkg>), or move the policy into each project's own package.jsonallowScripts field.
Summary
Setting
allow-scriptsin a user.npmrc(which npm's own warning recommends for global installs, and which is a valid config source for project installs) makes any tool launched vianpx/npm execthat shells out to a project-scopednpm installfail with:npm execexports the resolved npm config into the child process's environment asnpm_config_*variables. Because the outer process readallow-scriptsfrom a user.npmrc, the launched tool (and anything it spawns) inheritsnpm_config_allow_scripts, and when it reaches an inner project-scopednpm install, that inner npm resolves the value via itsenvsource — whichresolveAllowScriptsgroups withcliand rejects for non-global installs. The user never passed--allow-scripts; the value lives exactly where the error message tells them to put it.This is the
npm execsibling of #9783 (git-dependency preparation) and #9912/#9913 (npm run-scriptlifecycle export). The #9913 fix keeps persistentallow-scriptsout of lifecycle-exported config; thenpm execchild env export still forwards it (verified on 12.0.2 below).Environment
EALLOWSCRIPTSboth independently verified)How the offending setting gets there
Same as #9783 / #9912 — the documented workflow. Installing a global package with an install script prints:
Following the second suggestion writes
allow-scripts=<pkg>to the user.npmrc. From then on, everynpx-launched tool that performs project-scoped npm installs fails.Minimal, self-contained reproduction
Isolated
--userconfigso the reporter's own.npmrcis not involved:Actual result (B)
Export proof
On npm 12.0.2:
npm execstill setsnpm_config_allow_scriptsin the child environment, and an inner install with that variable present fails with the sameEALLOWSCRIPTSerror.Real-world impact
npx @robzolkos/lazypi— a community installer for the Pi coding agent that shells out topi install, which runsnpm install <pkg> --prefix <pi-dir> --legacy-peer-depsfor each package — fails on all 23 npm-backed packages at once with this error on any machine whose user.npmrccarries the recommendedallow-scriptsentry. The same applies to any scaffolder/bootstrap tool driven via npx that runs nested project-scoped npm installs. Notably, running the identical installer from a global install (plain Node child, nonpm execenv) works fine, which makes this particularly confusing to debug.Expected result
The npx-launched tool's inner install completes. A persistent user-level
allow-scriptspolicy is not a command-line flag;npm execshould not convert it into one by exporting it into the child environment.Root cause (source pointers)
lib/utils/resolve-allow-scripts.js—policyFromSources(npm, ['cli', 'env'])groups theenvsource withcli; a non-global, non-skipProjectConfiginstall throwsEALLOWSCRIPTSwhen that layer has a policy.npm execexports resolved config (including user.npmrcvalues such asallow-scripts) to the child process asnpm_config_*. fix(config): avoid exporting persistent allow-scripts #9913 excludedallow-scriptsfrom lifecycle exports; the exec path's export still includes it.Suggested fixes
npm execchild environment: keep persistentallow-scriptspolicy out of exec-exported config, so nested npm commands reload it from its original config source instead of treating it as an environment override.npm_config_allow_scriptsfrom the child env innpm exec— it is a one-off/global-context flag by design, so there is no valid exec-child use for it..npmrc" sends them in a circle — the entry already is in.npmrc.Related
.npmrcallow-scriptssetting is forwarded to git-dependency preparation as an env-layer policy and fails the install withEALLOWSCRIPTS#9783 — same misclassification, reached via git-dependency preparation's inner install (open)npm run-scriptlifecycle export; fixed for lifecycle exports onlyWorkaround
Tools/launchers: don't reach the tool through
npm exec(a globally installed copy runs with a clean environment and works). End users: keepallow-scriptsout of persistent user config and pass it per-invocation for global installs only (npm install -g <pkg> --allow-scripts=<pkg>), or move the policy into each project's ownpackage.jsonallowScriptsfield.