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
{{ message }}
Repository navigation
Agent mode misses an npm-aliased copy under install-strategy=linked (node_modules/.store/lp@…), so apply exits 0 with it unpatched and VEX attests not_affected #852
[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
#738 (fixing #356) taught the agent-mode resolver to treat a real dir whose own package.json names the patched name@version as a copy of it, so lp@npm:left-pad@1.3.0 is now patched in a hoisted tree. Under npm's install-strategy=linked, though, npm 9–11 put the alias in its own store entry named after the alias: node_modules/.store/lp@1.3.0-<hash>/node_modules/lp. The top-level node_modules/lp is a symlink to it. Agent mode never reaches that copy:
Alias plus a plain copy ("left-pad": "1.3.0" and "lp": "npm:left-pad@1.3.0"): apply patches only the left-pad@1.3.0-<hash> store entry and exits 0. vex then writes not_affected for pkg:npm/left-pad@1.3.0, while require('lp') loads the unpatched file.
Alias only:apply exits 0 with 0 of 1 targeted patch applied … 1 not found on disk and the note "targets a package not installed on this host (resolved by the project lockfile; skipped)". The package is installed. vex refuses with package_not_found, which fails safe, but the diagnostic is wrong.
Impact
A false not_affected VEX statement for code the app actually loads, with a success exit and no warning (the mixed case). This is the #356 symptom that #738 fixed for hoisted trees, still present for linked trees on npm 9.4–11.
Repro (Linux, npm 10.9.4 / Node 22, main 4646693; no network beyond the registry)
mkdir p &&cd p
echo'{"name":"p","version":"1.0.0","private":true,"dependencies":{"left-pad":"1.3.0","lp":"npm:left-pad@1.3.0"}}'> package.json
echo'install-strategy=linked'> .npmrc
npm install --no-audit --no-fund
readlink -f node_modules/left-pad node_modules/lp
# …/node_modules/.store/left-pad@1.3.0-iv4j8hdajpqgDc7lVr5hdA/node_modules/left-pad# …/node_modules/.store/lp@1.3.0-NCKE2NXgCY5tgWWRE6qdYA/node_modules/lp# hand-stage a patch for pkg:npm/left-pad@1.3.0 (marker prepended to index.js)
python3 - <<'PY'import hashlib, json, osdef h(b): return hashlib.sha256(b"blob %d\0" % len(b) + b).hexdigest()o = open("node_modules/left-pad/index.js","rb").read(); a = b"/* SOCKET-PATCHED */\n" + oos.makedirs(".socket/blobs", exist_ok=True)for b in (o, a): open(".socket/blobs/" + h(b), "wb").write(b)json.dump({"patches": {"pkg:npm/left-pad@1.3.0": {"uuid": "1a2b3c4d-5e6f-4a1b-8c2d-0123456789ab", "exportedAt": "2026-01-01T00:00:00Z", "files": {"package/index.js": {"beforeHash": h(o), "afterHash": h(a)}}, "vulnerabilities": {"GHSA-aaaa-bbbb-cccc": {"cves": ["CVE-2024-99999"], "summary": "s", "severity": "high", "description": "d"}}, "description": "d", "license": "MIT", "tier": "free"}}}, open(".socket/manifest.json", "w"))PY
socket-patch apply --offline # exit 0: "1 of 1 targeted patch applied"
socket-patch vex --offline -O v.json # exit 0: "status": "not_affected"
node -e "for (const m of ['left-pad','lp']) console.log(m, require('fs').readFileSync(require.resolve(m),'utf8').slice(0,20))"# left-pad /* SOCKET-PATCHED */# lp /* This program is f <- unpatched
Drop "left-pad": "1.3.0" from package.json for the alias-only case: apply reports 1 not found on disk (exit 0) and vex exits 1 with package_not_found.
Actual: the alias's store entry is skipped. With a plain copy also installed, the run reports full success and VEX attests not_affected for bytes that are still unpatched.
Matrix (Linux; each cell run at least twice, apply run twice per cell)
npm
Node
strategy
alias + plain
alias only
9.9.4
22
linked
fail (lp unpatched, VEX not_affected)
not run
10.9.4
22
linked
fail
fail (not found on disk, exit 0; VEX refuses)
11.6.2
22
linked
fail
fail
12.2.0
24
linked
pass (npm 12 dedupes the alias into the left-pad@1.3.0-<hash> entry)
macOS and Windows weren't probed (probe branches are paused). The resolver logic is OS-independent.
First bad version
Not a regression. Alias installs were never patched before #738 (#356), and #738 covered the hoisted layout only.
Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:2893 and :2899: the store-variant scan drops any entry whose advertised name (lp, taken from the .store dir name) differs from the package.json name, then probes entry_nm.join(&full_name) (…/node_modules/left-pad). An aliased entry holds …/node_modules/lp instead.
list_npm_store_entries_sync (npm_crawler.rs:2491) derives the entry's name from the dir name. For npm's linked store, the entry's own package.json is the authority.
[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
#738 (fixing #356) taught the agent-mode resolver to treat a real dir whose own
package.jsonnames the patchedname@versionas a copy of it, solp@npm:left-pad@1.3.0is now patched in a hoisted tree. Under npm'sinstall-strategy=linked, though, npm 9–11 put the alias in its own store entry named after the alias:node_modules/.store/lp@1.3.0-<hash>/node_modules/lp. The top-levelnode_modules/lpis a symlink to it. Agent mode never reaches that copy:"left-pad": "1.3.0"and"lp": "npm:left-pad@1.3.0"):applypatches only theleft-pad@1.3.0-<hash>store entry and exits 0.vexthen writesnot_affectedforpkg:npm/left-pad@1.3.0, whilerequire('lp')loads the unpatched file.applyexits 0 with0 of 1 targeted patch applied … 1 not found on diskand the note "targets a package not installed on this host (resolved by the project lockfile; skipped)". The package is installed.vexrefuses withpackage_not_found, which fails safe, but the diagnostic is wrong.Impact
A false
not_affectedVEX statement for code the app actually loads, with a success exit and no warning (the mixed case). This is the #356 symptom that #738 fixed for hoisted trees, still present for linked trees on npm 9.4–11.Repro (Linux, npm 10.9.4 / Node 22, main
4646693; no network beyond the registry)Drop
"left-pad": "1.3.0"frompackage.jsonfor the alias-only case:applyreports 1 not found on disk (exit 0) andvexexits 1 withpackage_not_found.Expected vs actual
left-pad@1.3.0is patched, whatever its dir name, and VEX attests only when all of them are. CLI_CONTRACT.md (updated in Fix agent mode skipping npm-aliased copies (#356) #738) says alias installs are patched copies, and npm install-strategy=linked: transitive packages under node_modules/.store are "not installed", and scan --apply exits 0 leaving them unpatched #359 / Fix npm store copies missed by agent apply and vex (#601, #603) #605 extended agent mode to npm's.storelayout. The hoisted control on the same npm (install-strategy=hoisted) passes: both copies are patched andrequire('lp')loads the patched file.not_affectedfor bytes that are still unpatched.Matrix (Linux; each cell run at least twice,
applyrun twice per cell)left-pad@1.3.0-<hash>entry)left-pad@…)macOS and Windows weren't probed (probe branches are paused). The resolver logic is OS-independent.
First bad version
Not a regression. Alias installs were never patched before #738 (#356), and #738 covered the hoisted layout only.
Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:2893and:2899: the store-variant scan drops any entry whose advertised name (lp, taken from the.storedir name) differs from thepackage.jsonname, then probesentry_nm.join(&full_name)(…/node_modules/left-pad). An aliased entry holds…/node_modules/lpinstead.node_modules/lpsymlink into.storeisn't followed either.list_npm_store_entries_sync(npm_crawler.rs:2491) derives the entry's name from the dir name. For npm's linked store, the entry's ownpackage.jsonis the authority.