Repository navigation
In a yarn classic Plug'n'Play project, vex attests a hosted patch as not_affected while the copy .pnp.js loads is still unpatched #519
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:yarn-classicYarn classic (1.x)Yarn classic (1.x)
on Oct 2, 2026 mikolalysenko commented
on Oct 2, 2026 CollaboratorAuthorMore actions[agent] New information from the Yarn Berry bug-hunt routine (ledger #305): this also reproduces on yarn berry PnP, on main
61cfb9b, Linux.Setup: a
nodeLinker: pnpproject installed from the registry lock, so.pnp.cjsand.yarn/cachehold the unpatchedleft-pad@npm:1.3.0. Then the hosted lock from a lock-only checkout is pulled in (left-pad@npm:1.3.0::__archiveUrl=…plus its10c0checksum), and standalonevex --output v.json --product pkg:npm/app@1.0.0runs beforeyarn install. I used the repo's owne2e_redirect_yarn_berry_buildfixture (wiremock patch API, real10c0checksum bootstrap).OS yarn node -r ./.pnp.cjsloadsstandalone vexLinux 4.0.2 unpatched verified/not_affected"(redirected)", exit 0 (2/2 runs)Linux 4.12.0 unpatched verified/not_affected, exit 0 (2/2)Linux 4.18.1 unpatched verified/not_affected, exit 0 (2/2)Linux 4.12.0, after yarn install --immutablepatched (attestation now true) Berry-specific notes for the fix:
- docs/testing/yarn-berry-compatibility.md:11 says that under PnP "standalone
vexstill attests a hosted lock'schecksum:pin", and thepnp-linkercell intests/yarn_berry_common/mod.rs:958asserts it, but only after a fresh install. So on berry, a blanket "PnP ⇒ not crawled" fix like the one proposed above would flip a documented, tested contract. A narrower check is possible on berry: a stale install is detectable, because the.pnp.cjspackage registry (and.yarn/install-state.gz) still names the registry locatorleft-pad@npm:1.3.0, not the::__archiveUrl=locator that the lock now pins. - The suspect code is the same:
crates/socket-patch-cli/src/commands/vex.rs:603-611(package_not_found+lockfile_basis+crawled()).
Generated by Claude Code
- docs/testing/yarn-berry-compatibility.md:11 says that under PnP "standalone
mikolalysenko commented
on Oct 2, 2026 CollaboratorAuthorMore actions[agent] Triaged:
priority:p1(yarn classic and berry, npm family). Not a duplicate, and no open fix PR.Related to #493 and #518 (also "vex reads an uncrawled install as absent"), but the cause is different. Those two have a real
node_modulestree that crawl-root discovery misses, and they'll be fixed in the crawler. Under PnP there is no tree to crawl. The fix belongs in the lockfile-basis excuse incrates/socket-patch-cli/src/commands/vex.rs: a PnP loader (.pnp.js/.pnp.cjs) should count as "not crawled" for npm purls. On berry it needs the narrower stale-install check from the comment above, so the documentedpnp-linkercontract still holds after a fresh install. Left unclustered.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Re-triage on main
e61a845, after #978 changed PnP detection to follownodeLinker: this still reproduces. Yarn 1.22.22, Linux, run twice. The issue's exact repro gives the same result: a lock-only CI checkout pins (redirected: 1),node -r ./.pnp.jsstill loads the unpatchedleft-pad, andsocket-patch vexexits 0 withverified/not_affectedforpkg:npm/left-pad@1.3.0. #978 correctly treats a loader next to a classic lock as live, butvexnever asks. PR #1033 is still open.
Generated by Claude Code
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
Yarn classic 1.12+ supports Plug'n'Play (
"installConfig": {"pnp": true}in package.json). Installs then write a.pnp.jsloader that resolves packages straight out of the yarn cache, and there's nonode_modules/.scanalready knows it can't see these packages: every mode emitsyarn_pnp_unsupported("socket-patch cannot discover or patch them in ANY mode").Standalone
socket-patch vexdoesn't apply that refusal. Onceyarn.lockcarries a hosted pin, for example committed from a lock-only CI checkout where no.pnp.jsexists yet and the hosted rewrite goes through,vexsees no installed copy (the crawler can't look inside PnP). It then attests the patch from the lock pin, even though.pnp.jsstill loads the unpatched cache copy.Impact
A signed-off
not_affectedstatement for a vulnerable package that is actually running. A developer or CI job that pulls the hosted lock and runsvexbeforeyarn installgets a false attestation. Nothing warns, andvexexits 0.Repro
I ran this against a local mock patch API (
--api-url,SOCKET_PATCH_SERVER_URL).Expected vs actual
(redirected)row) says a post-installvex"hash-verifies the installed copy the build consumes — or, with nothing installed, attests a discovered lockfile reference from its integrity pin". The "Manifest-less VEX" row adds that "installed evidence wins", and that a purl the crawler didn't look at (the--ecosystemscase) must stay omitted because "not installed" has to mean the crawler looked. In a PnP project the crawler structurally can't look;scan's ownyarn_pnp_unsupportedwarning says so.vexshould therefore omit the purl (or refuse withyarn_pnp_unsupported), not attest it. A defaultnode_modulesproject in the same state is correctly omitted withnot_applied(exit 1).vextreats the PnP-installed copy as absent and attestsnot_affectedfrom the lock pin.Matrix (Linux, main
61cfb9b).pnp.js+ hosted pin →vexnode_modules(control)not_applied(exit 1)After a real
yarn install --frozen-lockfile,.pnp.jsloads the patched hosted copy, so the attestation becomes true. The bug is the window where it isn't.First bad: release 4.0.0 isn't affected: the same
vexexits 2 withmanifest_not_found, because it has no manifest-less VEX. The bug arrives with the v5 lockfile-basis attestation on main.Suspect code
crates/socket-patch-cli/src/commands/vex.rs:603-611: thepackage_not_found→ lockfile-attested excuse only checkscrawled(), which is the--ecosystemsfilter. It doesn't check whether the npm crawler could see the project's layout at all. A yarn PnP loader (.pnp.js/.pnp.cjs, detected incrates/socket-patch-core/src/crawlers/pkg_managers.rs) should make npm purls "not crawled", exactly like an--ecosystemsexclusion.vexattests a hosted patch as not_affected (verified) while the installed copy under node_modules/.bun is still unpatched (v5 regression) #405 (Bun isolated store), npm crawler never looks in Rush's common/temp store: hostedvexattests a transitive dep not_affected while its installed copy is unpatched, and agent apply reports it package_not_installed #518 (Rushcommon/temp), and Agent mode ignores yarn classic's--modules-folder: packages installed there are reported "not installed" andscan --mode agentexits 0 leaving them unpatched #493 (yarn classic--modules-folder, see the comment there). Yarn berry PnP probably shares this path; that wasn't tested here.