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
Bun hosted and vendored rewiring rewrites bundled: true lock entries that Bun never fetches: the bundled copy stays unpatched, scan reports success, and vendored vex attests not_affected #469
Bun unpacks these from the parent's tarball and never fetches them. That's the same reason #325 / #337 made npm skip and contest inBundle copies. The Bun backends have no such handling:
Hosted (scan --mode hosted) rewrites the bundled entry to the Socket URL. It reports redirected: 1, status: success and no warning. npm emits redirect_npm_bundled_instance_skipped for the same shape.
Vendored (scan --mode vendored) rewrites it to .socket/vendor/npm/<uuid>/…tgz, also silently.
After a fresh bun install --frozen-lockfile, the copy the parent actually loads (node_modules/<parent>/node_modules/<pkg>) is unpatched. On text locks with Bun ≥ 1.2, Bun also hoists an extra, patched top-level copy from the rewritten entry, which nothing requires.
Vendored vex (default, with verification) attests not_affected for that purl on every Bun version and lock format. On Bun 1.1.45 and on bun.lockb there is no patched copy anywhere on disk. Hosted vex --no-verify attests too, although --no-verify must skip only the hashing, never the wiring/contest gates. Hosted default vex does refuse (not_applied), because its installed-tree check sees the bundled copy.
vex/discover/bun.rs and both Bun rewriters never look at bundled (grep -n bundled returns nothing in any *bun* source file).
Impact
A project whose dependency bundles a vulnerable package gets a successful hosted/vendored run and, in vendored mode, a verified OpenVEX not_affected statement, while the code that actually runs is the unpatched bundled copy. It's the Bun twin of #325, which was fixed for npm only.
Repro (Linux, any Bun ≥ 1.1.39; mock patch API, no secrets)
Fixture: a scoped package @bh/[email protected] with "bundleDependencies": ["is-number"], shipping node_modules/is-number (7.0.0) inside its tarball, served from a local registry scope. A mock patch API serves a hosted/vendored patch for pkg:npm/[email protected] that prepends /* SOCKET-PATCHED */ to index.js. The routes are the same ones e2e_redirect_bun_build.rs mocks: patches/batch, by-package, patches/package, view/<uuid>, plus the hosted tarball.
Hosted is the same with --mode hosted: redirected: 1, no warning, the bundled copy unpatched after the frozen install, and vex --no-verify exits 0 with not_affected.
Expected vs actual
Expected: CLI_CONTRACT.md, "Contested locks": "A bundled npm copy … of the same name@version contests the reference … npm unpacks it from the parent package's tarball, so no rewire reaches it and it stays unpatched." Bun's bundled: true entry has exactly those semantics. So the rewriters should skip it with a warning (like redirect_npm_bundled_instance_skipped / vendor_bundled_instance_skipped), or refuse like vlt's vendor_bundled_deps_unsupported. VEX should report patched_ref_unattributable and not attest, including under --no-verify (the contract's "Liveness gates": --no-verify skips only the hashing).
Actual: the bundled entry is rewired silently, the run succeeds, and vendored vex (verified) and hosted vex --no-verify both attest not_affected while the loaded copy is unpatched.
Matrix (Linux; real Bun from npm @oven/bun-linux-x64; main d984832; shape: bundled copy only)
Bun
lock
hosted scan
vendored scan
bundled copy after frozen install
hoisted phantom copy
vendored vex
hosted vex
hosted vex --no-verify
1.1.45
text v0
success, no warning
success, no warning
unpatched
none
not_affected
not_applied (ok)
not_affected
1.1.45
bun.lockb
success
success
unpatched
none
not_affected
not_applied
not_affected
1.2.23
text v1
success
success
unpatched
patched, unused
not_affected
not_applied
not_affected
1.3.14
text v1
success
success
unpatched
patched, unused
not_affected
not_applied
not_affected
1.4.2
text v2
success
success
unpatched
patched, unused
not_affected
not_applied
not_affected
1.4.2
bun.lockb
success
success
unpatched
none
not_affected
not_applied
not_affected
Each 1.4.2 text cell reproduced on 2+ fresh runs. The "both" shape (the project also depends on [email protected] directly) gives the same result: both entries are rewired, and the bundled copy stays unpatched. macOS and Windows weren't probed. The behaviour is in lockfile parsing and rewriting, which isn't OS-specific.
First bad version: not a regression. Release 4.0.0 behaves the same, and also attests in hosted default vex.
Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:3633 (rewrite_bun_lock entry loop: matches on the spec only, not the {meta}.bundled flag)
crates/socket-patch-core/src/vendor/bun_lock.rs:285 / :1013 (vendored text rewrite)
crates/socket-patch-core/src/patch/redirect/bun_binary.rs:18, crates/socket-patch-core/src/vendor/bun_binary.rs:25 (binary lock: the bundled record is rewritten too)
[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).
Summary
Bun records a package's
bundleDependenciesinbun.lockas their own entries, keyedparent/childand carrying{ "bundled": true }:Bun unpacks these from the parent's tarball and never fetches them. That's the same reason #325 / #337 made npm skip and contest
inBundlecopies. The Bun backends have no such handling:scan --mode hosted) rewrites the bundled entry to the Socket URL. It reportsredirected: 1,status: successand no warning. npm emitsredirect_npm_bundled_instance_skippedfor the same shape.scan --mode vendored) rewrites it to.socket/vendor/npm/<uuid>/…tgz, also silently.bun install --frozen-lockfile, the copy the parent actually loads (node_modules/<parent>/node_modules/<pkg>) is unpatched. On text locks with Bun ≥ 1.2, Bun also hoists an extra, patched top-level copy from the rewritten entry, which nothingrequires.vex(default, with verification) attestsnot_affectedfor that purl on every Bun version and lock format. On Bun 1.1.45 and onbun.lockbthere is no patched copy anywhere on disk. Hostedvex --no-verifyattests too, although--no-verifymust skip only the hashing, never the wiring/contest gates. Hosted defaultvexdoes refuse (not_applied), because its installed-tree check sees the bundled copy.vex/discover/bun.rsand both Bun rewriters never look atbundled(grep -n bundledreturns nothing in any*bun*source file).Impact
A project whose dependency bundles a vulnerable package gets a successful hosted/vendored run and, in vendored mode, a verified OpenVEX
not_affectedstatement, while the code that actually runs is the unpatched bundled copy. It's the Bun twin of #325, which was fixed for npm only.Repro (Linux, any Bun ≥ 1.1.39; mock patch API, no secrets)
Fixture: a scoped package
@bh/[email protected]with"bundleDependencies": ["is-number"], shippingnode_modules/is-number(7.0.0) inside its tarball, served from a local registry scope. A mock patch API serves a hosted/vendored patch forpkg:npm/[email protected]that prepends/* SOCKET-PATCHED */toindex.js. The routes are the same onese2e_redirect_bun_build.rsmocks:patches/batch,by-package,patches/package,view/<uuid>, plus the hosted tarball.Hosted is the same with
--mode hosted:redirected: 1, no warning, the bundled copy unpatched after the frozen install, andvex --no-verifyexits 0 withnot_affected.Expected vs actual
name@versioncontests the reference … npm unpacks it from the parent package's tarball, so no rewire reaches it and it stays unpatched." Bun'sbundled: trueentry has exactly those semantics. So the rewriters should skip it with a warning (likeredirect_npm_bundled_instance_skipped/vendor_bundled_instance_skipped), or refuse like vlt'svendor_bundled_deps_unsupported. VEX should reportpatched_ref_unattributableand not attest, including under--no-verify(the contract's "Liveness gates":--no-verifyskips only the hashing).vex(verified) and hostedvex --no-verifyboth attestnot_affectedwhile the loaded copy is unpatched.Matrix (Linux; real Bun from npm
@oven/bun-linux-x64; maind984832; shape: bundled copy only)vexvexvex --no-verifyEach 1.4.2 text cell reproduced on 2+ fresh runs. The "both" shape (the project also depends on
[email protected]directly) gives the same result: both entries are rewired, and the bundled copy stays unpatched. macOS and Windows weren't probed. The behaviour is in lockfile parsing and rewriting, which isn't OS-specific.First bad version: not a regression. Release 4.0.0 behaves the same, and also attests in hosted default
vex.Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:3633(rewrite_bun_lockentry loop: matches on the spec only, not the{meta}.bundledflag)crates/socket-patch-core/src/vendor/bun_lock.rs:285/:1013(vendored text rewrite)crates/socket-patch-core/src/patch/redirect/bun_binary.rs:18,crates/socket-patch-core/src/vendor/bun_binary.rs:25(binary lock: the bundled record is rewritten too)crates/socket-patch-core/src/vex/discover/bun.rs:119(discovery takes the bundled entry as a live Socket ref, and has no bundled contest likevex/discover/npm.rsgot in Fix npm VEX attesting packages with an unpatched bundled copy (#325) #337)Related: #325 (npm, fixed by #337), #405 (another Bun VEX false attestation).