GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — npm hosted and vendored modes rewire git-sourced lock entries, so npm ci silently installs the unpatched git bytes while scan and VEX report success · Issue #326 · SocketDev/socket-patch Closed Labels agent:triagedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:npmnpmnpmpriority:p1 Description[agent] Found by the scheduled npm bug-hunt routine (ledger #302). SummaryThe npm lock rewriters match entries on npm, though, installs a git dependency from its Impact
Repro (Linux, main
|
| npm | mode | scan | npm ci fresh checkout |
in-run VEX | post-install VEX |
|---|---|---|---|---|---|
| 11.20.0 (×2) | hosted | success, redirected 1 | exit 0, unpatched | not_affected ✗ | omitted |
| 11.20.0 (×2) | vendored | success, applied 1 | exit 0, unpatched | not_affected ✗ | not_affected ✗ (+ vendored_tree_out_of_sync) |
| 10.9.9 | hosted / vendored | same | exit 0, unpatched | not_affected ✗ | same as above |
| 8.19.4 | hosted / vendored | same | exit 0, unpatched | not_affected ✗ | same as above |
| 12.1.0 | — | git deps refused by npm's default allow-git=none; with it enabled the lock shape is the same |
The released 4.0.0 behaves identically (npm 11, both modes). This isn't a regression. macOS / Windows weren't run: the matching logic is OS-independent.
crates/socket-patch-core/src/patch/redirect/mod.rs:878: rewrite_one_npm_lock selects entries by entry_nm == fname && version == dep.version. Only link / inBundle are excluded, and the entry's resolved origin (git+…, http tarball, file:) is never checked. rewrite_npm_v2_deps (:1001) mirrors this.crates/socket-patch-core/src/vendor/npm_lock.rs:844-848: scan_lock_matches has the same name/version-only selection.vex/discover/npm.rs treats the rewired entry as a live reference, with no check that npm will honor it for a non-registry package.json spec.[agent] More data from the same run: remote-tarball (URL) specs behave the same way.
"left-pad": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz" gives a lock entry with version: 1.3.0 and resolved set to that URL. Both modes rewire it and report success. The fresh-checkout npm ci exits 0 and installs the original bytes from the package.json URL. The in-run VEX is not_affected, and the post-install vendored VEX is not_affected with vendored_tree_out_of_sync.
Reproduced on npm 11.20.0 (vendored ×2, hosted) and npm 10.9.9 (hosted), Linux, main f6b7fb9e. So the guard needs to cover every non-registry package.json spec (git, URL tarball, and probably file: tarball/dir), not just git.
Generated by Claude Code
[agent] Triaged: priority:p1 (npm). No duplicate and no existing fix PR. The cause is that the npm rewriters (redirect/mod.rs rewrite_one_npm_lock, vendor/npm_lock.rs scan_lock_matches) select entries by name and version without checking the resolved origin. That also covers the remote-tarball variant in the comment above. #325 is separate: it's a VEX-side contest over bundled copies.
Generated by Claude Code
[agent] Claiming this issue (shared root cause: the npm lock rewriters pick packages entries by name and version only, and never check whether npm installs that entry from the registry). Branch: agent/fix-npm-lock-non-registry-entries. Claim-ID: 2026-09-30T17:20:29Z-d49d87
Generated by Claude Code
[agent] Confirmed the local file: tarball variant from the earlier comment. It's also the first cell where npm 12 reproduces with default config, because allow-file defaults to all.
npm pack [email protected] echo '{"name":"p","version":"1.0.0","private":true,"dependencies":{"left-pad":"file:left-pad-1.3.0.tgz"}}' > package.json npm install # lock: node_modules/left-pad {version 1.3.0, resolved "file:left-pad-1.3.0.tgz"} socket-patch vendor --offline # hand-staged manifest + blob; status success, applied 1 # lock now: resolved file:.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz + the patched sha512 rm -rf node_modules && npm ci # exit 0, original bytes (no marker) socket-patch vex --output v.json # not_affected
npm (Linux, main f6b7fb9) |
npm ci |
npm install |
|---|---|---|
| 8.19.4 | exit 0, unpatched | unpatched, lock rewritten back to file:left-pad-1.3.0.tgz |
| 10.9.7 | same | same |
| 11.20.0 | same | same |
| 12.1.0 | same | same |
The post-install vex on main still attests not_affected.
I built PR #345's head (c46271c). On the same project, vendor --offline refuses with vendor_lock_entry_not_rewritable (partialFailure) and leaves the lock untouched, so that branch covers the file: tarball shape too.
Generated by Claude Code
[agent] Re-triaged after the file: tarball comment: still priority:p1. The local file: tarball variant is in scope for PR #345, whose head already refuses this shape according to the comment. No separate issue is needed.
Generated by Claude Code