Skip to content

Hosted and vendored npm scans break npm 12 allowScripts pins (pkg@x.y.z), so approved install scripts are silently blocked (or every npm ci fails under strict-allow-scripts) #1595

Closed

Description

[agent] Found by the scheduled npm bug-hunt routine (ledger #302).

Summary

npm 12 blocks dependency install scripts by default. Projects approve them in package.json#allowScripts, and npm approve-scripts <pkg> writes a version-pinned key by default ("esbuild@0.19.12": true). npm only matches a registry-style key (pkg, pkg@1.2.3) against a lock entry whose resolved is a registry tarball URL (…/<name>/-/<leaf>-<ver>.tgz). It reads the trusted name and version from that URL (@npmcli/arborist/lib/script-allowed.js, isRegistryNode / getTrustedRegistryIdentity).

A hosted scan rewrites resolved to https://patch.socket.dev/patch/npm/t/<uuid>/<leaf>.tgz. A vendored scan rewrites it to file:.socket/vendor/npm/<uuid>/<leaf>.tgz. Neither URL has the registry shape, so the pinned approval stops matching:

  • Default npm 12 config: the next npm ci installs the patched package but skips its approved postinstall / install script. npm prints "install scripts blocked because they are not covered by allowScripts". socket-patch exits 0 and prints no warning. For native-addon packages (sharp, bcrypt, esbuild's binary check and so on), the install ends up broken.
  • strict-allow-scripts=true: every npm ci fails (npm error --strict-allow-scripts: 1 package(s) have install scripts not covered by allowScripts: esbuild@0.19.12) until the pin is rolled back.

A name-only key ("esbuild": true) keeps working. The only fixes npm offers are worse. Re-running npm approve-scripts esbuild over a hosted pin replaces the pinned approval with name-only esbuild: true, which weakens the policy. Over a vendored pin, it writes an absolute, machine-specific key ("file:/home/me/proj/.socket/vendor/npm/<uuid>/esbuild-0.19.12.tgz": true) that doesn't match on any other checkout or in CI.

Impact

In any npm 12 project that uses the default (pinned) allowScripts entries, a hosted or vendored scan of a package with install scripts disables those scripts, or breaks every strict install. The scan reports success. vex exits 0 and attests the patch (the files are patched), while the package's install step never ran.

Repro

Run against current main (657fce2), with a local mock of the public patch API (SOCKET_PROXY_URL / SOCKET_API_URL plus --patch-server-url) serving a patch for esbuild@0.19.12 (lib/main.js + one comment line):

mkdir at && cd at
cat > package.json <<'EOF'
{"name":"at","version":"1.0.0","dependencies":{"esbuild":"0.19.12"},
 "allowScripts":{"esbuild@0.19.12":true}}
EOF
npm install                                   # npm 12.2.0
rm -rf node_modules && npm ci --loglevel=info | grep 'run esbuild@0.19.12 postinstall'   # runs
socket-patch scan --mode hosted               # or --mode vendored; exit 0, no warning
rm -rf node_modules && npm ci --loglevel=info
#  npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
#  npm warn install-scripts   esbuild@0.19.12 (postinstall: node install.js)
echo strict-allow-scripts=true >> .npmrc
rm -rf node_modules && npm ci                 # exit 1, --strict-allow-scripts error
socket-patch rollback && rm -rf node_modules && npm ci   # exit 0 again

Expected vs actual

  • Expected: a hosted or vendored scan doesn't change which install scripts npm runs. If it can't keep an allowScripts approval valid, it warns, the way it already warns for the other npm 12 install gates (redirect_npm_allow_remote for allow-remote, vendor_npm_allow_file for allow-file, see docs/testing/npm-compatibility.md). docs/testing/npm-compatibility.md says npm 12 is "patched with a plain npm ci", and the scan's next steps say a reinstall picks up the patched artifacts. Neither mentions that approved install scripts stop running.
  • Actual: exit 0 and no warning. The scripts are blocked, or with strict-allow-scripts the install fails.

Matrix (Linux, Node 22.22.0, run 2026-10-16)

npm mode allowScripts key postinstall before scan after scan + npm ci
12.0.0 / 12.1.0 / 12.2.0 hosted esbuild@0.19.12 runs blocked
12.0.0 / 12.1.0 / 12.2.0 vendored esbuild@0.19.12 runs blocked
12.0.0 / 12.1.0 / 12.2.0 hosted / vendored esbuild (name-only) runs runs
12.2.0 hosted esbuild@0.19.12 + strict-allow-scripts=true runs npm ci exit 1
11.21.1, 10.9.4, 7.24.2 hosted / vendored any runs runs (no default-deny)

Each npm 12 cell reproduced at least twice. macOS and Windows weren't run (probe branches are blocked for this routine). npm's matcher is platform-independent.

First bad version

Not a socket-patch regression: no release reads allowScripts. It became reachable when npm 12.0.0 started blocking install scripts by default.

Suspect code

  • crates/socket-patch-core/src/hosted/engine.rs:2890 is where the npm hosted run emits its other npm 12 install-gate warning (redirect_npm_allow_remote). Nothing there reads package.json#allowScripts.
  • crates/socket-patch-core/src/vendor/npm_lock.rs:1588 (vendor_npm_allow_file) is the vendored counterpart.
  • Possible directions: warn (or refuse) when a rewritten entry has hasInstallScript: true and a pinned allowScripts key covers it. Or, for hosted, serve a tarball URL whose path keeps npm's registry shape (/<name>/-/<leaf>-<ver>.tgz), so npm's versionFromTgz still derives the trusted name and version.

Activity

  1. mikolalysenko commented on Oct 16, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged as p1 (npm). Confirmed on main 657fce2: nothing in crates/socket-patch-core/src reads package.json#allowScripts, so neither the hosted nor the vendored npm rewrite warns. Related to #1597 (pnpm build approvals) but not the same root cause (different matcher and writer), so not clustered.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 16, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] New data from the scheduled npm bug-hunt routine (ledger #302), main 657fce2, Linux, Node 22.22.0.

    npm 12.2.1 (published 2026-10-15, next-12) still has this bug. Its arborist (10.0.3 → 10.0.4) changes script-allowed.js, but only for node_modules/.store link targets (npm/cli#9939). Registry identity still needs a registry-shaped resolved.

    npm install-strategy key hosted vendored
    12.2.0 hoisted esbuild@0.19.12 blocked (repro) —
    12.2.1 hoisted esbuild@0.19.12 blocked blocked
    12.2.1 linked esbuild@0.19.12 blocked blocked
    12.2.0 / 12.2.1 linked esbuild (name only) runs runs

    In every row, the npm install before the scan runs the postinstall without a warning. After the scan, a fresh npm ci prints install scripts blocked because they are not covered by allowScripts: esbuild@0.19.12 (postinstall: node install.js). The patched bytes are installed in every cell.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 21, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: npm rewrites never check package.json#allowScripts, so a pinned approval silently stops matching the rewritten resolved). Branch: agent/fix-npm-allow-scripts-pins. Claim-ID: 2026-10-21T12:23:52Z-fb4054


    Generated by Claude Code

  4. mikolalysenko commented on Oct 21, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1657


    Generated by Claude Code

  5. added 5 commits that reference this issue on Oct 21, 2026
    f5cf6e1
    46ccb14
    63b4504
    6c41e51
    cd0cf07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions