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 thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 68/100
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
[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.
- Ngôn ngữ chính
- Rust
- Star
- 8
- Fork
- 0
- Merge trung bình
- 15 giờ 39 phút
- Pull request đã merge (30 ngày)
- 104
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của SocketDev/socket-patch
-
agent:triaged bug bughunt pm:cargo priority:p2
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
SocketDev/socket-patch#651 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent:claimed agent:triaged arch-audit bug pm:hatch priority:p1
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 88/100
SocketDev/socket-patch#613 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent:claimed agent:triaged arch-audit bug priority:p3
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
SocketDev/socket-patch#571 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent:triaged bug bughunt pm:composer priority:p2
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 90/100
SocketDev/socket-patch#515 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent:triaged bug bughunt pm:npm priority:p1
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
SocketDev/socket-patch#464 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của SocketDev/socket-patch
Issue tương tự
-
area:release bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
registrystack/registry-stack#1874 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
component:midnight-toolkit status:untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
midnightntwrk/midnight-node#2237 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày