Repository navigation
Hosted yarn classic scan --vex attests not_affected when an npm: alias copy of the patched package was skipped, while standalone vex refuses the same lock #1081
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 7, 2026 - added a commit that references this issue
on Oct 7, 2026 mikolalysenko commented
on Oct 7, 2026 CollaboratorAuthorMore actions[agent] Triage:
priority:p1(Yarn classic, npm-family). Not a duplicate. Open PR #1033 (arch-fix/vex-false-attest) doesn't touchassume_applied's handling ofredirect_yarn_classic_alias_skipped(I checked its diff), so it doesn't cover this. Related: #828 (the same alias lock state on rollback / remove), which has a different cause.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Re-checked on main
ea09714(after #1033 / #1044 / #1083): still reproduces, ×2, on yarn 1.22.22.{"left-pad":"1.3.0","lp":"npm:left-pad@1.3.0"}→scan --mode hosted --vex vex.json --jsonexits 0 and pinsleft-pad@1.3.0:. It warnsredirect_yarn_classic_alias_skippedand the in-run VEX statement isnot_affected/inline_mitigations_already_exist. Afterrm -rf node_modules && yarn install --frozen-lockfile,node_modules/left-padis patched andnode_modules/lpis not. A standalonevexon the same lock refuses with exit 2 (the "copy stays UNPATCHED and nothing is attested" warning). So the in-run and standalone paths still disagree.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (with #1158; shared root cause: the hosted rewrite reports no per-patch signal for a yarn npm: alias copy it skipped, so the in-run VEX (assume_applied) and the takeover planner (Takeover::unpinned) both treat the purl as fully pinned). Branch: agent/fix-yarn-alias-skip-partial-pin. Claim-ID: 2026-10-08T21:44:16Z-5531e1
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions- added a commit that references this issue
on Oct 8, 2026 - addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). The normal scan --vex workflow must not attest an npm alias copy that the same scan explicitly skipped. Standalone and embedded VEX need the same outcome; PR #1180 is pending.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
Take a yarn 1.22.22 project that depends on the patched package directly and through an
npm:alias ("left-pad": "1.3.0","x": "npm:left-pad@1.3.0"). yarn 1.22.22 writes two lock blocks,left-pad@1.3.0:and"x@npm:left-pad@1.3.0":.A hosted scan pins the direct block and leaves the alias block alone, with
redirect_yarn_classic_alias_skipped(documented). After the next install,node_modules/xis the unpatched upstream copy.vexsees this. It warnspatched_ref_unattributable("that copy stays UNPATCHED and nothing is attested") and exits 2 with nothing written, both lock-only and after the install.scan --mode hosted --vexcarries the samepatched_ref_unattributablewarning invex.warnings[], yet writes anot_affectedstatement forpkg:npm/left-pad@1.3.0.So the run's own envelope says "nothing is attested" next to a document that attests.
Impact
CI that runs
scan --mode hosted --vexpublishes anot_affectedOpenVEX statement for a vulnerability whose code still ships unpatched under the alias name. The scan exits 0.Repro (Linux, main
05ecc6e, yarn 1.22.22, local mock patch API on :8787)A
file:./left-pad-1.3.0.tgzdirect dep instead of the registry one behaves the same way.Expected vs actual
npm:aliases"): the alias entry "is left untouched … that copy keeps the unpatched artifact". Theassume_appliedcontract incommands/vex.rssays an envelope must never attest a CVE its own run left unpatched, and the Bun hosted and vendored rewiring rewritesbundled: truelock entries that Bun never fetches: the bundled copy stays unpatched, scan reports success, and vendoredvexattests not_affected #469 bundled-copy case is already excluded on that basis. The in-run document should match standalonevex: no statement for the package (or the scan fails--vexas standalone does).not_affectedis written, exit 0.Matrix (Linux, Node 22; each cell twice)
scan --vexvex(lock-only / post-install)node_modules/xfile:tarball + aliasleft-pad@1.3.0, "x@npm:left-pad@1.3.0":, pinned as a wholeIn my runs, every release from 1.0 to 1.22.21 (checked 1.12.3, 1.17.3, 1.19.0, 1.21.1, 1.22.0/4/10/15/17/19/21) merges the two keys into one block. Only 1.22.22, the current latest and corepack's default, writes them separately.
Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1337:params.assume_applieddrops the uuids inrewrite.bundled_skipped_uuids(#469), but not those whose copy the rewriter skipped as an alias (redirect_yarn_classic_alias_skipped). So the confirmed purl is attested without verification, althoughvex/discoverflags itpatched_ref_unattributable. Berry'sredirect_yarn_berry_alias_skippedmay take the same path (not checked).Related: #828 (the same lock state also can't be unwound by
rollback/remove; commented there).