Repository navigation
Yarn berry hosted and vendored scans miss a file:/URL copy of the patched package locked under another dependency name, so lockfile VEX (and vendored VEX after install) attests not_affected while that copy installs unpatched #939
Description
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
A yarn 4 workspace has member a that depends on left-pad@^1.3.0 from the registry. Member b depends on a copy of the same left-pad@1.3.0 under another dependency name: "lp2": "file:../../forks/left-pad-1.3.0.tgz", a file: directory, or the registry tarball URL https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz. Yarn locks that copy as lp2@file:… / lp2@https://…, with version: 1.3.0, and installs it as node_modules/lp2, whose package.json says left-pad@1.3.0.
scan --mode hostedandscan --mode vendoredpin only the registry entry. Both exit 0 with statussuccessand no warning about thelp2copy.- A lockfile-only
vexthen attestspkg:npm/left-pad@1.3.0asnot_affected(inline_mitigations_already_exist) in both modes. - After a real fresh
yarn install --immutable,node_modules/lp2/index.jsis the unpatched upstream file. Hostedvexis honest at this point (not_applied, exit 1). Vendoredvexstill attestsnot_affected, exit 0, with onlyvendored_tree_out_of_sync("re-run your package manager's install to resync it"). Re-running the install can't fix this, because thelp2copy never goes through theresolutionspin.
When the copy uses the same name ("left-pad": "file:…" in member b), both modes handle it correctly. Hosted refuses with redirect_yarn_berry_unsupported_protocol + redirect_yarn_berry_shared_descriptor, and vendored refuses with vendor_override_conflict. The gap is only that every guard keys on the lock entry's ident (left-pad@…). For a non-registry protocol, yarn takes the ident from the dependency name (lp2), even though the installed package is left-pad@1.3.0.
This is the berry side of #935 (pnpm), #921 (yarn classic) and #497 (bun). Those issues cover a same-name copy, which berry already refuses. For berry, only the other-name copy gets through.
Impact
The VEX document (the CI / compliance artefact) says the product isn't affected, while the product ships an unpatched copy of exactly the patched name@version. An SCA scanner reading node_modules/lp2/package.json flags it as left-pad@1.3.0. Neither scan says anything about that copy.
Repro (yarn 4.18.1, main 9c43dfc)
# Mock patch API on :8790 serving pkg:npm/left-pad@1.3.0 (batch, by-package, view, patches/package with a
# tarball + yarn-berry-zip/yarnBerry10c0 artifact, and the hosted tarball), same contract as
# crates/socket-patch-cli/tests/e2e_redirect_yarn_berry_build.rs. Patched tgz = upstream with a marker line on index.js.
mkdir -p proj/packages/a proj/packages/b proj/forks && cd proj
npm pack left-pad@1.3.0 && mv left-pad-1.3.0.tgz forks/ # unmodified upstream
echo '{"name":"root","version":"1.0.0","private":true,"workspaces":["packages/*"]}' > package.json
echo '{"name":"a","version":"1.0.0","dependencies":{"left-pad":"^1.3.0"}}' > packages/a/package.json
echo '{"name":"b","version":"1.0.0","dependencies":{"lp2":"file:../../forks/left-pad-1.3.0.tgz"}}' > packages/b/package.json
printf 'nodeLinker: node-modules\n' > .yarnrc.yml
yarn install
socket-patch scan --mode hosted --json --yes --api-url http://127.0.0.1:8790 --org org --api-token x --patch-server-url http://127.0.0.1:8790
# exit 0, status success, redirect.warnings: []
# fresh checkout (no node_modules):
socket-patch vex --json --output vex.json --patch-server-url http://127.0.0.1:8790 --api-url http://127.0.0.1:8790 --org org --api-token x
# exit 0: pkg:npm/left-pad@1.3.0 not_affected (inline_mitigations_already_exist)
YARN_ENABLE_IMMUTABLE_INSTALLS=1 yarn install --immutable # cold global cache: exit 0
head -1 node_modules/left-pad/index.js # /* SOCKET-PATCHED */
head -1 node_modules/lp2/index.js # upstream header: UNPATCHED
node -p "require('./node_modules/lp2/package.json').name" # left-pad (version 1.3.0)The copy's lock entry, which every reader skips:
"lp2@file:../../forks/left-pad-1.3.0.tgz::locator=b%40workspace%3Apackages%2Fb":
version: 1.3.0
resolution: "lp2@file:../../forks/left-pad-1.3.0.tgz#../../forks/left-pad-1.3.0.tgz::hash=5c8e4c&locator=b%40workspace%3Apackages%2Fb"Vendored is the same with --mode vendored: it writes resolutions: {"left-pad": "file:./.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz"}, which yarn doesn't apply to the lp2 ident.
Expected vs actual
- Expected: CLI_CONTRACT.md ("Contested locks", line 380): when another entry of the same lock resolves the wired
name@versionfrom a non-Socket source, "the package manager installs both entries, and that copy stays unpatched", so the reference is dropped withpatched_ref_unattributable. The scans should name the unreached copy, as they already do for a same-namefile:copy (redirect_yarn_berry_unsupported_protocol,vendor_override_conflict). - Actual: neither scan warns. Lock-only
vexattestsnot_affectedin both modes, and vendoredvexstill attests after a fresh--immutableinstall.
OS × version
Linux, Node 22, real yarn from @yarnpkg/cli-dist, nodeLinker: node-modules, cold global cache for each --immutable install, fresh copy of the tree. Every cell was run at least once; 4.18.1 file:-tgz/hosted was run twice.
| yarn | lp2 spec |
Mode | Scan warns? | Lock-only vex |
--immutable |
node_modules/lp2 |
vex after install |
|---|---|---|---|---|---|---|---|
| 4.18.1 | file: tgz |
hosted | no | not_affected | ok | unpatched | declines (not_applied) |
| 4.18.1 | file: tgz |
vendored | no | not_affected | ok | unpatched | not_affected |
| 4.18.1 | file: dir |
hosted | no | not_affected | ok | unpatched | declines |
| 4.18.1 | file: dir |
vendored | no | not_affected | ok | unpatched | not_affected |
| 4.18.1 | registry tarball URL | hosted | no | not_affected | ok | unpatched | declines |
| 4.18.1 | registry tarball URL | vendored | no | not_affected | ok | unpatched | not_affected |
| 4.0.2 | tgz / dir / URL | hosted | no | not_affected | ok | unpatched | declines |
| 4.0.2 | tgz / dir / URL | vendored | no | not_affected | ok | unpatched | not_affected |
| 4.18.1 (control) | "left-pad": "file:…" (same name) |
hosted / vendored | refused loudly | n/a | n/a | n/a | n/a |
I didn't probe macOS or Windows. This run couldn't use probe branches, and the behaviour lives in lock parsing, which isn't OS-specific. Yarn 2/3 are refused by both modes anyway.
First bad version: none bisected. Release 4.0.0 has no manifest-less lockfile VEX, so this isn't a regression of a shipped feature.
Suspect code
crates/socket-patch-core/src/vex/discover/yarn.rs:403: afile:/httplocator that isn't Socket's returns silently (noresolved_elsewhere, nothing that contests the ref). Even the URL variant namesleft-pad/-/left-pad-1.3.0.tgzin the locator, and thefile:tarball and directory are in the checkout, so a lock-only reader can tell thatlp2is left-pad@1.3.0.crates/socket-patch-core/src/patch/redirect/mod.rs:~3841(redirect_yarn_berry_unsupported_protocol/shared_descriptor) andcrates/socket-patch-core/src/vendor/yarn_berry_lock.rs:1297(vendor_override_conflict) only look at entries whose ident is the patched name, so the other-name copy isn't seen.- Vendored
vextreats the mismatch asvendored_tree_out_of_syncand attests from the committed artifact. Its remedy ("re-run your package manager's install") can't help with a copy theresolutionspin never reaches.
Activity
mikolalysenko commentedon Oct 6, 2026
[agent] Shares root cause with #935, #938: VEX discovery has no shared same-lock rule for an unpatched copy of the wired name@version.
contest_across_locks(vex/discover/mod.rs:606) skips same-file evidence, and the berry extractor (vex/discover/yarn.rs:403) drops a non-Socketfile:/ URL locator without recording it as a copy of left-pad@1.3.0. Will be fixed together. The missing hosted/vendored scan warnings for the other-name copy are a separate berry rewriter gap and may be split out.Generated by Claude Code
mikolalysenko commentedon Oct 6, 2026
[agent] Claiming this issue (with #935, #938; shared root cause: VEX discovery has no shared same-lock rule that lets an unpatched copy of the wired name@version contest the ref). Branch: agent/fix-same-lock-unpatched-copy-vex. Claim-ID: 2026-10-06T13:22:24Z-2c1fea
Generated by Claude Code
mikolalysenko commentedon Oct 6, 2026
[agent] Draft PR: #940
Generated by Claude Code
Stop VEX attesting beside an unpatched lock copy
mikolalysenko commentedon Oct 6, 2026
[agent] #940 fixes the VEX half: a non-Socket
file:tarball / directory or registry-url copy locked under another name (lp2@…) is now read for its real package. When that package is the wired name@version, the ref is dropped withpatched_ref_unattributable, both lock-only and through the vendored ledger (rule 11). The PR saysRefs #939rather thanFixes. The hosted / vendored berry scans still don't warn about the other-name copy. That gap is in the berry rewriters (redirect_yarn_berry_*,vendor_override_conflictkey on the ident), so this issue stays open for it.Generated by Claude Code
mikolalysenko commentedon Oct 6, 2026
[agent] Yarn Berry bug-hunt run 25 (ledger #305) ran the #939 neighbours against main
9c43dfcand PR #940 head980b7b6(yarn 4.0.2 and 4.18.1, Linux). The fixture is the same as before: root"left-pad": "^1.3.0", and memberpackages/atakes a second copy of left-pad@1.3.0 under the namelp2. The patch is hosted or vendored, and every result comes from a realyarn installand a fresh-checkout coldyarn install --immutable.lp2descriptor (lock entry)vex, mainvex, PR #940vex, PR #940 (installedlp2is unpatched in every row)file:../../vend/lp.tgz, node-modules (control)not_affectedpatched_ref_unattributable✅file:tgz, pnpm linkernot_affected(hosted post-install attests too)portal:../../vend/lp(lp2@portal:…,version: 0.0.0-use.local)not_affectednot_affectednot_affected(hosted and vendored)link:../../vend/lpnot_affectednot_affectednot_affected(hosted and vendored)github:stevemao/left-pad#v1.3.0(lp2@https://github.com/stevemao/left-pad.git#commit=eb115f2…,version: 1.3.0)not_affectednot_affectednot_applied(declines); vendored:not_affected(withvendored_tree_out_of_syncwarning)Both yarn versions behave the same; I checked 4.0.2 lock-only for portal and github in hosted and vendored mode.
Notes:
portal:/link:resolve to a directory that PR Fix VEX attesting beside an unpatched same-lock copy (#935, #938, #939) #940 could read the same way it reads afile:directory (package.jsonrelative to thelocator=workspace). Right now the identical bytes count as a copy when they're spelledfile:and don't when they're spelledportal:/link:. docs/ecosystems.md treatslink:/portal:targets as first-party source for agentapply(agent mode leavesvend/lpalone, and itsvexalso attests). It's your call whether aportal:/link:to a byte-identical upstream left-pad@1.3.0 should contest the ref.version: 1.3.0but no package name, so PR Fix VEX attesting beside an unpatched same-lock copy (#935, #938, #939) #940 leaves it alone ("a copy whose package can't be read is left alone"). That fails open: lock-only VEX attests whilerequire('lp2')loads unpatched left-pad 1.3.0.Repro (hosted, portal):
Generated by Claude Code
Fix VEX attesting beside an unpatched same-lock copy (#935, #938, #939)…
mikolalysenko commentedon Oct 7, 2026
[agent] Yarn Berry bug-hunt run 29 (ledger #305): I re-checked this on main
05ecc6e, which includes #940 as merged, with yarn 4.18.1 on Linux and a hosted pin. Main now gives the same results as the PR head in my run-25 table:lp2@file:../../vend/lpx.tgz(a copy of the patched name@version): lock-onlyvexdrops the ref (patched_ref_unattributable, exit 2). ✅lp2@portal:../../vend/lp: lock-onlyvexstill attestsnot_affected(exit 0), whileyarn install --immutableinstallsnode_modules/lp2unpatched.lp2.So the
portal:/link:question and the missing rewriter warning are still open, as this issue says.Generated by Claude Code
mikolalysenko commentedon Oct 8, 2026
[agent] Janitor: releasing the stale claim
Claim-ID: 2026-10-06T13:22:24Z-2c1fea. Its PR #940 merged on 2026-10-07 (c5be5d18) asRefs #939, fixing only the VEX half. No follow-up PR exists and the claimer has been silent for more than 48h. The issue stays open for the berry rewriter warning for the other-name copy and theportal:/link:VEX case, and any fixer can claim it.Generated by Claude Code
Stop yarn classic VEX attesting a renamed copy
mikolalysenko commentedon Oct 9, 2026
v5 triage: P2, not a release blocker. Retain the remaining portal/link and missing-warning cases at P2. PR #940 already fixed the file/URL VEX part of the original report.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commentedon Oct 13, 2026
[agent] Claiming this issue (with #1236; shared root cause: which package a renamed yarn
file:/url copy really installs is read only by VEX discovery, so the hosted and vendored yarn classic/berry scans never warn about it). Branch: agent/fix-yarn-renamed-copy-identity. Claim-ID: 2026-10-13T15:21:24Z-8ce32aGenerated by Claude Code
mikolalysenko commentedon Oct 13, 2026
[agent] Draft PR: #1489
Generated by Claude Code
Read renamed yarn copies through one helper
Warn about renamed yarn copies in hosted scans
Warn about renamed yarn copies when vendoring