Repository navigation
Gem hosted redirect and setup ignore BUNDLE_GEMFILE from .bundle/config, so they wire Gemfile while bundler loads the configured manifest unpatched (VEX and setup --check still pass) #390
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:bundlerBundler (RubyGems)Bundler (RubyGems)
on Sep 30, 2026 mikolalysenko commented
on Sep 30, 2026 CollaboratorAuthorMore actions[agent] Triaged as priority:p1 (Bundler). Related in shape to #341 (manifest chosen by filename instead of what Bundler loads), but #341 is about
gems.rbprecedence in vendored mode; this one is theBUNDLE_GEMFILEsetting in hosted mode andsetup. A fix at one "which manifest does Bundler load" helper would likely cover both; kept separate for now.
Generated by Claude Code
mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions[agent] Re-triaged on main
2463257(after #277, which removedsetup, so thesetuphalf of this issue no longer applies). The hosted half still reproduces, and vendored mode has the same gap. Both runs used Bundler 4.0.17 on Ruby 3.3.6 (Linux), withBUNDLE_GEMFILE: "Gemfile.next"added to the project's.bundle/configandGemfile.next/Gemfile.next.lockcopied from the originals.- Hosted (
e2e_redirect_gem_buildcapstone,scan --mode hosted --vex): the scan exits 0 withredirected: 1and lists onlyGemfileas rewritten.Gemfile.nextstill readsgem "vuln-gem"from the upstream source, yet the in-run VEX saysnot_affected("Patched via Socket patch … (redirected)"). No warning mentionsBUNDLE_GEMFILE. - Vendored (
e2e_vendor_gem_builddirect-dep capstone, rack ~> 3.1, prebuilt service artifact):vendorexits 0 withapplied: 1and wires onlyGemfile/Gemfile.lock.Gemfile.nextstaysgem "rack", "~> 3.1". On a fresh checkout that keeps.bundle/config, the frozenbundle installsucceeds, butbundle execloads upstream rack (probe constant missing after require).
crates/socket-patch-core/src/vendor/gem.rs:86-87hardcodesGemfile/Gemfile.lock, so a single "which manifest does Bundler load" helper would also cover vendored mode (and #341).
Generated by Claude Code
- Hosted (
mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (with #341). Shared root cause: there is no single "which manifest does Bundler load" resolver. Hosted and vendored modes pick the Gemfile by filename, or hardcode
Gemfile, and ignoregems.rbprecedence andBUNDLE_GEMFILE. Branch: agent/fix-bundler-manifest-resolution. Claim-ID: 2026-10-01T06:22:10Z-b5b0c8
Generated by Claude Code
mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions- added 5 commits that reference this issue
on Oct 1, 2026 mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions[agent] Bundler 2.4.22 has the same problem (Linux, Ruby 3.3.6, main
6e7ef74). The project has.bundle/configset toBUNDLE_GEMFILE: "gemfiles/app.gemfile"and a stray rootGemfile.scan --mode hostedreportsrewrittenFiles: ["Gemfile"], and neithergemfiles/app.gemfilenorgemfiles/app.gemfile.lockgets a patch-registry entry. That's the same result as the 4.0.17 cell already recorded here.
Generated by Claude Code
[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).
Summary
Bundler takes its manifest from
BUNDLE_GEMFILE: from the environment, or from the project's.bundle/config(bundle config set --local gemfile Gemfile.next, stored asBUNDLE_GEMFILE: "Gemfile.next"). That's the standard dual-boot / next-Rails layout (Gemfile+Gemfile.next+Gemfile.next.lock).socket-patch never consults that setting (there's no
BUNDLE_GEMFILEreference anywhere incrates/). It always picksgems.rborGemfileby filename (crates/socket-patch-core/src/patch/redirect/mod.rs:6051-6070,crates/socket-patch-core/src/setup/gem/mod.rs:101-116). It does already read the same.bundle/configforBUNDLE_PATH(crates/socket-patch-core/src/crawlers/ruby_crawler.rs:30-48).The result:
scan --mode hosted/get --mode hosted) rewritesGemfile+Gemfile.lock, reportsstatus: success,redirected: 1with no warnings, and the in-run VEX attestsnot_affected (redirected).bundle installthen resolves fromGemfile.next, still pointed at upstream, and the app loads the unpatched gem.setupappends thepluginblock toGemfile.setup --checkexits 0 ("configured"), but bundler never reads that file, so the plugin never registers. Afterbundle pristine+bundle installthe gem stays unpatched with no warning.(The post-install
socket-patch vexdoes notice:not_applied, no document. So the false attestation is the in-run one, the same shape as #341.)Repro (Bundler 4.0.17, Ruby 3.3.6, Linux)
Hermetic fixture: a mock upstream compact index + patch registry + patches API (a kept-alive copy of
crates/socket-patch-cli/tests/e2e_redirect_gem_build.rs), servingvuln-gem 1.0.0with a free patch.setupvariant, on the same layout:Expected vs actual
gems.rbvsGemfile("the gem rewriter picks the pair bundler reads",crates/socket-patch-cli/src/commands/scan/hosted.rs:83-85; docs/ecosystems.md: "editsgems.rb+gems.lockedwhen present (bundler prefers them overGemfile)"). Otherwise it should fail closed with a warning, likeredirect_gem_gemfile_spellings_diverge, and never emit anot_affectedattestation or a passingsetup --checkfor a file bundler ignores.Gemfile, reports success, attestsnot_affected, andsetup --checkpasses, while bundler installs and loads upstream bytes.Matrix
setup+--checkBUNDLE_GEMFILE/config gemfilebehave the same since Bundler 1.xThe env-var-only form (
BUNDLE_GEMFILE=Gemfile.next bundle installin a CI job) has the same outcome. It's arguably harder for socket-patch to see, but the committed.bundle/configform is on disk in the project, where the crawler already readsBUNDLE_PATH.Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:6051-6070: the(gemfile_name, lock_name)choice considers onlygems.rb/Gemfile.crates/socket-patch-cli/src/commands/scan/hosted.rs:81-88: the fixed list of gem manifest names handed to the rewriter.crates/socket-patch-core/src/setup/gem/mod.rs:101-116:discover_bundler_projectignoresBUNDLE_GEMFILE.plugins.rb.tmplalso hard-codesGemfile.lockindigest_inputs.crates/socket-patch-core/src/vendor/gem.rs) most likely shares the gap. I didn't verify it this run.Tested on main
f6b7fb9(v4.0.0).