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
[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
npm aliases ("lp": "npm:left-pad@1.3.0") install the real left-pad@1.3.0 bytes under node_modules/lp/, and its package.json says "name": "left-pad". Agent-mode apply never finds that copy:
Alias-only project:apply reports skipped / package_not_installed ("No installed package matches this PURL"), exits partialFailure, and the installed copy stays unpatched.
Mixed project (a plain left-pad@1.3.0 plus an alias of the same name@version): apply patches node_modules/left-pad, reports success with no warning, and leaves node_modules/lp unpatched. Both apply --vex and a later socket-patch vex then attest pkg:npm/left-pad@1.3.0 as not_affected / inline_mitigations_already_exist, even though require('lp') loads the unpatched file.
Vendored mode handles the same alias correctly: vendor rewires the node_modules/lp lock entry ("name": "left-pad") to the vendored tarball. Only agent mode (the find_by_purls resolver) misses it.
Impact
The vulnerable code stays in the build for every consumer that imports the package through the alias. Aliases are common for side-by-side majors, for example "lodash4": "npm:lodash@4.17.20".
The OpenVEX document claims the vulnerability is mitigated when the shipped node_modules still holds an unpatched copy of the same name@version, so downstream scanners suppress a real finding.
Alias-only projects get a misleading package_not_installed error for a package that is installed.
Repro (Linux, main f6b7fb9, npm 12.1.0; reproduced twice)
mkdir app &&cd app
echo'{"name":"app","version":"1.0.0","private":true,"dependencies":{"left-pad":"1.3.0","lp":"npm:left-pad@1.3.0"}}'> package.json
npm install
# node_modules/left-pad and node_modules/lp both hold left-pad@1.3.0 (lp/package.json: "name": "left-pad")# hand-stage .socket/manifest.json + blobs for pkg:npm/left-pad@1.3.0 (a marker prepended to# package/index.js, same shape as crates/socket-patch-cli/tests/e2e_vendor_npm_build.rs# stage_patch_with_vuln), plus "setup": {"manual": ["npm"]}
socket-patch apply --json --offline --vex inrun.json
# status success, events [applied pkg:npm/left-pad@1.3.0], no warnings
head -c 20 node_modules/left-pad/index.js # /* SOCKET-PATCHED */
head -c 20 node_modules/lp/index.js # /* This program is f <- unpatched
node -e "console.log(require('fs').readFileSync(require.resolve('lp'),'utf8').slice(0,20))"# unpatched
socket-patch vex --output v.json --json --offline
# inrun.json and v.json: not_affected / inline_mitigations_already_exist for GHSA-xxxx-yyyy-zzzz
Alias-only variant: use {"dependencies":{"lp":"npm:left-pad@1.3.0"}} and socket-patch apply returns partialFailure, skippedpackage_not_installed. A scoped alias ("@x/pad": "npm:left-pad@1.3.0") behaves the same.
Expected vs actual
Expected: CLI_CONTRACT.md ("Monorepo / multi-project discovery model") says apply "patches a package by PURL against the manifest regardless of how deep in the dependency tree it was installed", and describes npm's multi-copy fan-out, where every copy of a name@version is patched. The purl is pkg:npm/left-pad@1.3.0 and the installed package's own package.json identity is left-pad@1.3.0, so the aliased directory is an installed copy of that purl. A VEX not_affected statement should also only come out when the build consumes patched bytes (Setup property 7: VEX reflects "on-disk verification").
Actual: aliased copies are never probed. The alias-only case reports package_not_installed, and the mixed case leaves the alias unpatched with a clean success and a not_affected attestation.
Not a regression: 3.3.0 and 4.0.0 behave the same.
Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:797 (find_by_purls): the resolver target's dir_key is built from the purl name, so only node_modules/<purl-name> is ever probed.
crates/socket-patch-core/src/crawlers/npm_crawler.rs:978-985 (visit_resolver_dir): it also requires found_name == target.dir_key. That correctly rejects a different package living under the purl's directory name, but it means a copy whose directory name differs from its package.json name (an alias) can never match. The vendored lock rewriter already resolves alias edges by the entry's name (vendor/npm_lock.rs:882), so the two modes disagree.
[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
npm aliases (
"lp": "npm:left-pad@1.3.0") install the realleft-pad@1.3.0bytes undernode_modules/lp/, and itspackage.jsonsays"name": "left-pad". Agent-modeapplynever finds that copy:applyreportsskipped/package_not_installed("No installed package matches this PURL"), exitspartialFailure, and the installed copy stays unpatched.left-pad@1.3.0plus an alias of the samename@version):applypatchesnode_modules/left-pad, reportssuccesswith no warning, and leavesnode_modules/lpunpatched. Bothapply --vexand a latersocket-patch vexthen attestpkg:npm/left-pad@1.3.0asnot_affected/inline_mitigations_already_exist, even thoughrequire('lp')loads the unpatched file.Vendored mode handles the same alias correctly:
vendorrewires thenode_modules/lplock entry ("name": "left-pad") to the vendored tarball. Only agent mode (thefind_by_purlsresolver) misses it.Impact
"lodash4": "npm:lodash@4.17.20".node_modulesstill holds an unpatched copy of the samename@version, so downstream scanners suppress a real finding.package_not_installederror for a package that is installed.Repro (Linux, main
f6b7fb9, npm 12.1.0; reproduced twice)Alias-only variant: use
{"dependencies":{"lp":"npm:left-pad@1.3.0"}}andsocket-patch applyreturnspartialFailure,skippedpackage_not_installed. A scoped alias ("@x/pad": "npm:left-pad@1.3.0") behaves the same.Expected vs actual
Expected: CLI_CONTRACT.md ("Monorepo / multi-project discovery model") says
apply"patches a package by PURL against the manifest regardless of how deep in the dependency tree it was installed", and describes npm's multi-copy fan-out, where every copy of aname@versionis patched. The purl ispkg:npm/left-pad@1.3.0and the installed package's ownpackage.jsonidentity isleft-pad@1.3.0, so the aliased directory is an installed copy of that purl. A VEXnot_affectedstatement should also only come out when the build consumes patched bytes (Setup property 7: VEX reflects "on-disk verification").Actual: aliased copies are never probed. The alias-only case reports
package_not_installed, and the mixed case leaves the alias unpatched with a cleansuccessand anot_affectedattestation.OS × version
f6b7fb9not_affected)Not a regression: 3.3.0 and 4.0.0 behave the same.
Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:797(find_by_purls): the resolver target'sdir_keyis built from the purl name, so onlynode_modules/<purl-name>is ever probed.crates/socket-patch-core/src/crawlers/npm_crawler.rs:978-985(visit_resolver_dir): it also requiresfound_name == target.dir_key. That correctly rejects a different package living under the purl's directory name, but it means a copy whose directory name differs from itspackage.jsonname (an alias) can never match. The vendored lock rewriter already resolves alias edges by the entry'sname(vendor/npm_lock.rs:882), so the two modes disagree.