Global agent mode on pnpm 12 (and 11 without the global virtual store) patches only one of the per-install copies of a package, reports success, and VEX attests not_affected
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 68/100
Rechercherichtung
Start with crates/socket-patch-core/src/crawlers/npm_crawler.rs, especially resolve_pending_targets at line 922, get_global_node_modules_paths at 1135/1148, and find_store_peer_variant_copies at 1913. Reproduce the two pnpm global installs on /dev/shm using the issue's mock API setup, then compare the crawler with the project-mode layout and the e2e patterns in crates/socket-patch-cli/tests/e2e_redirect_pnpm_build.rs. Done means every physical copy is patched and get, apply, and vex no longer report success or not_affected while a copy remains unpatched.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
pnpm 11+ isolates global installs. Each pnpm add -g … command gets its own install directory, $PNPM_HOME/global/v11/<hash>/, with its own node_modules and, on pnpm 12 (or pnpm 11 with enableGlobalVirtualStore: false), its own node_modules/.pnpm virtual store. pnpm root -g returns the parent global/v11, and socket-patch uses that one directory as the global root.
When two global install groups both contain [email protected] (a direct pnpm add -g [email protected], plus a global tool that depends on left-pad), get -g / apply -g / scan -g --mode agent patch only one of the two physical copies. The tool keeps loading the unpatched copy. The run exits 0 with status: success, applied: 1, a re-run of apply -g says already_patched, and vex -g attests not_affected.
Which copy is missed depends on directory-listing order. When the group holding the direct left-pad link is listed first, the other group's .pnpm/[email protected] store entry is never probed. On ext4 that's about half of fresh setups; on tmpfs it's deterministic (see the repro).
Impact
A globally installed tool (any CLI installed with pnpm add -g) keeps running a vulnerable dependency while socket-patch reports it patched and emits a VEX statement saying the vulnerability isn't exploitable. Nothing in the JSON or on stderr shows that a copy was skipped.
Repro (Linux, pnpm 12.8.2, Node 22)
Uses /dev/shm so the listing order is deterministic. A local mock of the patch API serves a patch for pkg:npm/[email protected] that prepends /*SOCKET_PATCHED*/ to index.js (batch / by-package / view routes with inline blob content, as in crates/socket-patch-cli/tests/e2e_redirect_pnpm_build.rs).
# a global "tool" that depends on left-pad 1.3.0
mkdir wrap && cd wrap
echo '{"name":"lp-wrapper","version":"1.0.0","bin":{"lpw":"cli.js"},"dependencies":{"left-pad":"1.3.0"}}' > package.json
printf '#!/usr/bin/env node\nconsole.log(require("fs").readFileSync(require.resolve("left-pad"),"utf8").slice(0,18))\n' > cli.js
npm pack && cd ..
base=/dev/shm/g; mkdir -p $base/home/bin
export PNPM_HOME=$base/home HOME=$base PATH=$base/home/bin:$PATH
pnpm add -g ./wrap/lp-wrapper-1.0.0.tgz # group 1: left-pad is transitive (only in its .pnpm)
pnpm add -g [email protected] # group 2: left-pad is a direct global package
pnpm root -g # $base/home/global/v11
find $base/home -path '*left-pad/index.js' # two copies, one per global/v11/<hash>/node_modules/.pnpm
mkdir w && cd w
socket-patch get pkg:npm/[email protected] -g --yes --json --api-url $MOCK --org test-org --api-token fake
# exit 0, "status": "success", "applied": 1
lpw # "/* This program is" <- the tool still loads the original bytes
socket-patch apply -g --json --offline # success, left-pad: skipped / already_patched
socket-patch vex -g --offline --product pkg:npm/[email protected] --output v.json
# exit 0, one statement: not_affected, subcomponent pkg:npm/[email protected]
If you install the two groups in the opposite order, both copies are patched.
Expected vs actual
- Expected: agent mode patches every physical copy of a
name@version.find_by_purlsdocuments this ("Returns every physical copy … patching only one leaves a live, vulnerable copy while reporting success (a silent partial)"), as do docs/ecosystems.md (npm row: "any install layout … every store copy") and the agent-mode notes ("applyandrollbackpatch every store copy of aname@version"). VEX should not attest a patch that a loaded copy doesn't carry. - Actual: one copy is patched, the other stays original, and every command reports success.
OS × version (Linux, Node 22, main 2463257)
| pnpm | global layout | copies of [email protected] | result |
|---|---|---|---|
| 10.34.5 | single global/5, shared .pnpm |
1 | pass |
| 11.0.0 / 11.28.3 (default) | per-install dirs, global virtual store (store/v11/links) |
1 shared copy | pass here (the shared-store write is #361's problem) |
11.28.3, enableGlobalVirtualStore: false |
per-install .pnpm |
2 | fail (2 of 3 ext4 runs) |
| 12.4.2 | per-install .pnpm |
2 | fail |
| 12.8.1 | per-install .pnpm |
2 | fail (1 of 3 ext4 runs; order-dependent) |
| 12.8.2 | per-install .pnpm |
2 | fail: tmpfs 4/4 in the order above; on a fixed ext4 layout, 3/3 re-runs fail |
| 12.8.2, groups installed in the opposite order | per-install .pnpm |
2 | pass |
macOS and Windows weren't probed (no probe branch this run; see the ledger). The walk order there is filesystem-dependent too, so the miss should be possible there as well.
First bad commit
This is a regression. On the same ext4 layout, release 4.0.0 patched both copies in 3/3 clean runs, and main missed one in 3/3. Bisected on the deterministic tmpfs layout:
0b4e645(b32711f^): passb32711f"Support vlt in hosted, vendored and agent modes (#269)": first bad (reproduced twice)f6b7fb9,2463257(main): fail. Draft PR #365's head80f4a71also fails.
Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:922: inresolve_pending_targets,unmatched_namesis computed walk-wide. Once any importer tree has matchedleft-pad(group 2's direct link), every later pnpm store's entries for that name are filtered out, including a different install's own.pnpmthat holds a separate physical copy.npm_crawler.rs:972: since b32711f, inside a store entry only a real directory matches (is_real_package_dir_sync). Before that, group 1's.pnpm/lp-wrapper…/node_modules/left-padlink probably matched, which is how 4.0.0 reached the second copy.find_store_peer_variant_copies(npm_crawler.rs:1913) only fans out within the found copy's own virtual store, so it can't recover the other install's copy.get_global_node_modules_paths(npm_crawler.rs:1135,:1148) passes pnpm 11+'sglobal/v11as one root. Treating eachglobal/v11/<hash>/node_modulesas its own root (as for separate projects) would also avoid the cross-install filter. The analogous project-mode layout (asharedWorkspaceLockfile: falseworkspace, where each package has its own.pnpm) patches both copies correctly on pnpm 10.34.5 and 12.8.2, because those are separate roots.
- Vorherrschende Sprache
- Rust
- Sterne
- 8
- Forks
- 0
- Ø Merge
- 18 Std. 4 Min.
- Gemergte PRs (30 T.)
- 70
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus SocketDev/socket-patch
-
agent:triaged bug bughunt pm:composer priority:p2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 90/100
SocketDev/socket-patch#515 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
agent:triaged bug bughunt pm:npm priority:p1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
SocketDev/socket-patch#464 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
agent:triaged bug bughunt pm:npm priority:p1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
SocketDev/socket-patch#433 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
agent:triaged bug bughunt pm:uv priority:p1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
SocketDev/socket-patch#408 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
agent:triaged bug bughunt pm:yarn-berry priority:p1
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
SocketDev/socket-patch#370 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in SocketDev/socket-patch
Ähnliche Issues
-
discover: `sudo RTK_DISABLED=$VAR …` is not detected as a bypass when `sudo` is a transparent prefixOffenarea:cli bug good first issue priority:medium
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
rtk-ai/rtk#4412 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
skill:code-review
Schwierigkeit 1/5 1-3 Stunden Anfängerfreundlichkeit 88/100
Maintainer antworten meist innerhalb von 1 Tag
-
component:sight
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
agentic-os-org/ANOLISA#4115 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
rivet-dev/rivet#5819 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
A-io-database bug needs triage python
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 86/100
Maintainer antworten meist innerhalb von 1 Tag