You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Yarn classic VEX attests not_affected while a bundled copy of the patched package@version stays unpatched (yarn.lock has no inBundle, so the #325 fix can't see it) #758
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
This is the yarn classic version of #325. A yarn classic project can install the same name@version twice: once from its normal yarn.lock block, and once bundled inside another package's tarball (bundledDependencies). yarn.lock never records bundled copies. It has no inBundle / bundled flag, and no block for the bundled copy at all. So socket-patch can't tell the copy exists:
Hosted, in-run (scan --mode hosted --vex): attests not_affected. The run gives no warning; npm's equivalent is redirect_npm_bundled_instance_skipped.
Vendored, in-run and post-install (socket-patch vex after a fresh yarn install --frozen-lockfile): attests not_affected. Post-install, it does print vendored_tree_out_of_sync, but the remedy it gives ("re-run your package manager's install to resync it") can't work, because yarn re-extracts the bundled copy from its parent's tarball.
Hosted post-install vex: correct. It hash-checks every installed copy and omits the purl as not_applied.
Agent mode: correct. It patches both copies.
PR #669 (the open #325 fix) only adds bundled_skipped_uuids for package-lock.json (inBundle / legacy bundled). The yarn classic rewriter never sets it, so the hosted in-run path stays as it is. #337's VEX-discovery fix also keys on package-lock's inBundle, so it doesn't cover yarn.lock either.
Impact
A false VEX statement. The shipped node_modules contains an unpatched copy of the vulnerable name@version (node_modules/<parent>/node_modules/<pkg>), and the OpenVEX document says not_affected / inline_mitigations_already_exist. Downstream scanners then suppress the finding. In vendored mode the result is the same whether or not the tree was reinstalled.
Repro
This uses a local mock patch API (--proxy-url / --patch-server-url / --vendor-url) serving a free patch for left-pad@1.3.0 that prepends a marker to index.js. The bundling parent is a local tarball here for brevity. yarn handles registry packages with bundledDependencies the same way.
# parent package that bundles left-pad@1.3.0
mkdir -p bundsrc/package/node_modules/left-pad
tar xzf left-pad-1.3.0.tgz -C bundsrc/package/node_modules/left-pad --strip-components=1
echo'{"name":"bund","version":"1.0.0","dependencies":{"left-pad":"1.3.0"},"bundledDependencies":["left-pad"]}'> bundsrc/package/package.json
echo'module.exports=require("left-pad")'> bundsrc/package/index.js
tar czf bund-1.0.0.tgz -C bundsrc package
mkdir proj &&cd proj && git init -q && cp ../bund-1.0.0.tgz .echo'{"name":"proj","version":"1.0.0","dependencies":{"left-pad":"^1.3.0","bund":"file:./bund-1.0.0.tgz"}}'> package.json
yarn install # yarn.lock has no trace of the bundled copy
socket-patch scan --mode hosted --vex v0.json # (or --mode vendored) + mock URLs
grep '"status"' v0.json # "not_affected", no warning in either mode
rm -rf node_modules && yarn install --frozen-lockfile
head -c 25 node_modules/left-pad/index.js # /* SOCKET-PATCHED-HUNT */
head -c 25 node_modules/bund/node_modules/left-pad/index.js # /* This program is free s (unpatched)
socket-patch vex --output v1.json
# vendored: "not_affected" (+ vendored_tree_out_of_sync warning); hosted: purl omitted (correct)
Actual: hosted in-run and vendored (in-run and post-install) both attest not_affected. Neither mode warns at scan time, and the vendored post-install warning gives a remedy that doesn't fix it.
Matrix (Linux, Node 22, main 045d7ec)
yarn
hosted in-run --vex
hosted post-install vex
vendored in-run --vex
vendored post-install vex
scan-time bundled warning
1.7.0
not_affected (wrong)
omitted (correct)
not_affected (wrong)
not_affected (wrong)
none
1.10.1
not_affected (wrong)
omitted (correct)
not_affected (wrong)
not_affected (wrong)
none
1.22.22
not_affected (wrong)
omitted (correct)
not_affected (wrong)
not_affected (wrong, ×2)
none
Agent mode (scan --mode agent --vex) patches both copies and attests correctly (1.22.22). macOS and Windows weren't probed. The logic is OS-independent (lock-only rewriters plus VEX assembly).
Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1262: assume_applied only drops uuids in rewrite.bundled_skipped_uuids, and rewrite_yarn_classic (crates/socket-patch-core/src/patch/redirect/mod.rs:3060) never fills it. It can't from yarn.lock alone; it would need the installed tree, or the parents' bundledDependencies.
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
This is the yarn classic version of #325. A yarn classic project can install the same
name@versiontwice: once from its normalyarn.lockblock, and once bundled inside another package's tarball (bundledDependencies). yarn.lock never records bundled copies. It has noinBundle/bundledflag, and no block for the bundled copy at all. So socket-patch can't tell the copy exists:scan --mode hosted --vex): attestsnot_affected. The run gives no warning; npm's equivalent isredirect_npm_bundled_instance_skipped.socket-patch vexafter a freshyarn install --frozen-lockfile): attestsnot_affected. Post-install, it does printvendored_tree_out_of_sync, but the remedy it gives ("re-run your package manager's install to resync it") can't work, because yarn re-extracts the bundled copy from its parent's tarball.vex: correct. It hash-checks every installed copy and omits the purl asnot_applied.PR #669 (the open #325 fix) only adds
bundled_skipped_uuidsforpackage-lock.json(inBundle/ legacybundled). The yarn classic rewriter never sets it, so the hosted in-run path stays as it is. #337's VEX-discovery fix also keys on package-lock'sinBundle, so it doesn't cover yarn.lock either.Impact
A false VEX statement. The shipped
node_modulescontains an unpatched copy of the vulnerablename@version(node_modules/<parent>/node_modules/<pkg>), and the OpenVEX document saysnot_affected/inline_mitigations_already_exist. Downstream scanners then suppress the finding. In vendored mode the result is the same whether or not the tree was reinstalled.Repro
This uses a local mock patch API (
--proxy-url/--patch-server-url/--vendor-url) serving a free patch forleft-pad@1.3.0that prepends a marker toindex.js. The bundling parent is a local tarball here for brevity. yarn handles registry packages withbundledDependenciesthe same way.Expected vs actual
bundled: truelock entries that Bun never fetches: the bundled copy stays unpatched, scan reports success, and vendoredvexattests not_affected #469 / Fix in-run hosted VEX attesting npm bundled copies (#325) #669 establish for npm and Bun): VEX must not attest a patch while an installed copy of thatname@versionis still unpatched. The in-run--vexshould verify rather than assume, and the scan should warn that the bundled copy stays unpatched, as npm does withredirect_npm_bundled_instance_skipped/vendor_bundled_instance_skipped.not_affected. Neither mode warns at scan time, and the vendored post-install warning gives a remedy that doesn't fix it.Matrix (Linux, Node 22, main
045d7ec)--vexvex--vexvexAgent mode (
scan --mode agent --vex) patches both copies and attests correctly (1.22.22). macOS and Windows weren't probed. The logic is OS-independent (lock-only rewriters plus VEX assembly).Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1262:assume_appliedonly drops uuids inrewrite.bundled_skipped_uuids, andrewrite_yarn_classic(crates/socket-patch-core/src/patch/redirect/mod.rs:3060) never fills it. It can't from yarn.lock alone; it would need the installed tree, or the parents'bundledDependencies.crates/socket-patch-cli/src/commands/vex.rs:672-688: the vendored attestation stands on the committed artifact even when an installed copy differs. For a bundled copy, the "re-run your install" remedy is wrong, and the copy should block the attestation, as npm VEX attests not_affected while a bundled (inBundle) copy of the same package@version stays unpatched #325 does for npm.Related: #325 (npm, fix in #669), #497 (Bun's version of the npm-only #326 fix), #601 (bundled copies in vlt/pnpm agent mode).