Repository navigation
Hosted and vendored scans from a Bun workspace member with a stray bun.lock / bun.lockb pin that ignored lock, exit 0, and lock-only VEX attests not_affected while Bun installs the unpatched package #1101
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:bunBunBun
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Shares root cause with #1094: the workspace-member refusal in
crates/socket-patch-core/src/hosted/governing_root.rsis skipped wheneverhas_own_npm_family_lockfinds any npm-family lock in the member, includingbun.lock/bun.lockbthat Bun never reads inside a member. Will be fixed together.#1094 is in flight as PR #1095, which narrows the shortcut for npm locks only and leaves Bun out on purpose. The Bun half needs the same narrowing plus a regression test (stray member
bun.lockandbun.lockb, hosted and vendored, plusvexfrom the member).
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Bun bug-hunt run 31 (ledger #306): this still reproduces on main
829d0af, after #1044's governing-lock table landed. There's also a new variant: the workspace root holds a binarybun.lockb.Setup: Bun 1.4.2, a root
bun.lockb(saveTextLockfile = false) withworkspaces: ["packages/*"], and memberpackages/a(depends onleft-pad@1.3.0) holding a stray lock that a standalonebun installwrote.Stray member lock scan --mode hostedfrompackages/a(run twice)Fresh-clone bun install --frozen-lockfileLockfile-only vexfrom the memberbun.lock(text)exit 0, success, onlypackages/a/bun.lockmodifiedunpatched (root and member) n/a bun.lockbexit 0, success, onlypackages/a/bun.lockbmodifiedunpatched (root and member) exit 0, not_affected"Patched via Socket patch … (redirected)"The root
bun.lockbthat Bun actually installs from is untouched.vexrun in place against the unpatchednode_modulescorrectly refuses (exit 1). The text-root case still reproduces on829d0afas well (hostedscanfrom the member pins onlypackages/a/bun.lock, and the frozen install is unpatched).
Generated by Claude Code
- added a commit that references this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] #1134 (vlt) joins this cluster: the same
has_own_npm_family_lockshortcut inhosted::governing_root::refusalskips the vlt workspace-member refusal when the member holds a strayvlt-lock.json.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (with #1134; shared root cause: the workspace-member refusal is skipped whenever the member holds any npm-family lock, including a bun.lock/bun.lockb/vlt-lock.json its manager never reads inside a member). Branch: agent/fix-member-stray-bun-vlt-lock. Claim-ID: 2026-10-08T19:20:34Z-a94a0e
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Draft PR: #1161 (stacked on #1095, which fixes the npm half, #1094).
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] PR #1161 is ready for review. #1095 (the npm half) has merged; #1161 extends the same member check to Bun and vlt across hosted, vendored and vex.
Generated by Claude Code
[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).
Summary
This is the Bun variant of #1094. The fix for #1094, PR #1095, deliberately leaves Bun out: its comment says a member holding "a lock its own manager reads (pnpm, yarn, Bun, vlt…)" keeps the own-lock shortcut, and the #1094 thread says the Bun variant was kept out of scope because it wasn't tested. Tested here with real Bun: Bun never reads a lock inside a workspace member.
bun installat the root, andbun installrun inside the member, both walk up to the workspace root and install the member from the root'sbun.lock. A straypackages/a/bun.lockorbun.lockb, for example left behind when a package moved into a monorepo, is dead weight.On main, the #884 / #901 member refusal (
redirect_workspace_lockfile_elsewhere) is skipped whenever the member directory holds any npm-family lock (has_own_npm_family_lock, which includesbun.lockandbun.lockb). So a hostedscanorget <uuid>from such a member:bun.lock/bun.lockbwith the hosted pin,status: success,redirected: 1, exit 0, with no warning,bun.lockuntouched, so everybun install --frozen-lockfile(at the root or in the member) installs the unpatched package,socket-patch vexfrom the member then attestsnot_affected. That happens on a lockfile-only checkout, and on a hoisted install too, because the member has nonode_modulesof its own andvexfalls back to the member lock.scan --mode vendoreddoes the same thing: it vendors into the ignored member lock, writespackages/a/.socket/, exits 0, andvexattests.Impact
A signed-off VEX
not_affectedand a green CI step, while every install ships the vulnerable bytes. This is the same false-success shape as #884 and #1094, through a Bun lock.Repro
A local mock of the patch API serves one free patch for
left-pad@1.3.0, which prepends/* SOCKET-PATCHED */toindex.js.spissocket-patch … --api-url <mock> --org o --api-token fake --patch-server-url <mock>.get <uuid> --mode hostedfrom the member gives the same result (success,rewrittenFiles: ["bun.lock"]).Expected vs actual
redirect_workspace_lockfile_elsewhererow) says a hosted run from a workspace member "whose lock lives in another directory" is refused, because "the rewriters, which read only the project directory, would pin nothing". For Bun the governing lock is always the workspace root's, whatever sits in the member, so the refusal should fire (or at least a loud warning that names the stray lock). Vendored should refuse the member (vendor_lockfile_missing) as it does without the stray file.vexmust not attest a pin Bun never reads.not_affectedattestation, while Bun installs unpatched.Matrix (Linux, main
fe8455d)vexfrom memberbun.lockb.socket/writtennot_applied(membernode_moduleslinks the root store); lockfile-only checkout attestsbun.lockbcddf38d, hosted + vendoredControls: the same workspace from the root pins the root lock and a frozen install is patched (pass). macOS / Windows: not probed. The check is lock-path logic with no OS branch.
First bad version: none. Release 4.0.0 (npm
@socketsecurity/socket-patch-linux-x64-gnu) also exits 0 and pins the member lock (Bun 1.4.2), so it isn't a regression.Suspect code
crates/socket-patch-core/src/hosted/governing_root.rs:92:let workspace = if has_own_npm_family_lock(root) { None } else { … }.has_own_npm_family_lock(:247) countsbun.lock/bun.lockbfromOWN_LOCKS(:58).npm_member_stray_lock, but itsother_owncheck (governing_root.rs:316on the PR head) returnsNonewhenever the member holds a Bun lock, so Bun keeps the shortcut. Bun's rule is the same as npm's: a member of apackage.jsonworkspace whose root holdsbun.lock/bun.lockbis installed from the root lock. (Unlike yarn berry, Bun doesn't treat a nested lock as a separate project.)crates/socket-patch-core/src/vendor/lock_inventory/view.rs) likewise treats the member lock as the project's own.Related: #1094 / #1095 (npm), #884 / #901, #1097.
Probe runs: none (Linux sandbox only).