Cooldown does not fix the resolver
Bundler 2.6 cooldown defers new gem versions to interrupt published-and-pulled supply chain attacks. The resolver's trust model is the systemic exposure.
Bundler shipped cooldown support in version 2.6.0. The mechanism is narrow. Hold newly published gem versions out of the resolver for a configured number of days before they become candidates for installation. The default is zero. Opt-in via bundle config set cooldown <days> or per-gem in the Gemfile. The intent is supply chain defence against the well-documented pattern where a malicious gem version is published, pulled into production builds within minutes, and executed under the build identity before anyone notices the diff.
Cooldown is not the vulnerability. It is partial mitigation for the vulnerability. The actual exposure sits one layer down - in Bundler’s resolver and the trust model it inherits from RubyGems.org.
The resolver’s job is to compute a dependency graph that satisfies every version constraint declared in the Gemfile and the transitive constraints declared by each gem’s gemspec. It consults the index at rubygems.org, walks the constraints, and writes the resolved set to Gemfile.lock. The lockfile pins versions and checksums via the CHECKSUMS block introduced in Bundler 2.5. That checksum binds the resolved .gem artifact to a SHA256. It does not bind the artifact to a signer, a maintainer, or any out-of-band identity. It binds the artifact to itself. If the published artifact is malicious at publication time, the checksum is the checksum of a malicious artifact. The resolver is satisfied. The lockfile is consistent. The build is poisoned.
This is the design boundary. The resolver enforces version constraints and artifact integrity against the index. It does not, and cannot, enforce maintainer intent. Maintainer intent lives in RubyGems.org account control. Mandatory MFA exists for gems over the 165 million-download threshold - the policy RubyGems pushed in August 2022 after the rest-client incident. Below the threshold, accounts remain a single credential away from publication rights. Phishing the maintainer is the supply chain attack. Resolver behaviour is downstream.
Map this to MITRE T1195.002 - compromise software supply chain via dependency. The attacker does not breach the consumer. The attacker breaches the upstream maintainer account, publishes a tainted version against an existing gem name, and waits for bundle install and bundle update to deliver it. Initial access is the consumer’s own CI pipeline executing trusted code. T1059.006, Ruby command execution, follows trivially - gems run arbitrary code at install time via extconf.rb and at require time via the loaded source. There is no sandbox.
The historical record is concrete. rest-client 1.6.13, August 2019 - a maintainer account compromise published a version containing remote code execution that exfiltrated environment variables, including credentials, to an attacker-controlled Pastebin. strong_password 0.0.7, June 2019 - backdoored to fetch and eval a remote script under specific environment conditions, scoped to production Rails workloads. bootstrap-sass 3.2.0.3, April 2019 - a backdoor inserted between legitimate versions that responded to a magic cookie to execute attacker-supplied code. The pattern across all three is identical. Trusted name. Compromised release. Resolver pulls, build executes, exposure begins at the moment of the next install.
This is the pattern cooldown is designed to interrupt. The defence is temporal. Hold the version out of the resolution window long enough for the community detection cycle - security researchers, automated scanners, the maintainer themselves discovering the unauthorised push - to flag and yank the release before it reaches production builds. RubyGems-level yanks remove the version from the index. With cooldown set to seven days, a malicious gem published on day zero and yanked on day two never enters a downstream resolution. The resolver does not see it.
The topic framing inverts this. The framing claims cooldown creates a window for attackers to deploy compromised versions with minimal scrutiny. The mechanism does the opposite. Cooldown does not reduce scrutiny. It extends the scrutiny window by deferring consumer exposure. The attacker is not advantaged by the consumer waiting. The attacker is advantaged by the consumer pulling immediately, before the community has cycles to react. Cooldown is the consumer choosing not to be the canary.
Where the residual exposure remains is in three places.
First - cooldown is opt-in and the default is zero. The vast majority of bundle install invocations on the planet on June 6, 2026 will not have cooldown set. Builds that auto-update - Dependabot configurations with versioning-strategy: increase, Renovate with rangeStrategy: bump, scheduled bundle update cron jobs - pull the latest matching version the moment it lands. Cooldown is unset for them. The historical pattern of minutes-to-execution still applies.
Second - community detection is not guaranteed inside any specific window. The xz-utils CVE-2024-3094 backdoor, while not a Ruby gem, demonstrated upstream tradecraft sufficient to evade scrutiny for months. A maintainer-controlled compromise that ships gradual, plausible changes does not generate the immediate signal that an obvious credential stealer does. Seven days of cooldown does not detect what seven months of community review did not detect in another ecosystem. The defence depends on the attacker being noisy enough to be caught in the holding window.
Third - cooldown applies per-gem against the resolver. It does not validate maintainer identity continuity, does not detect maintainer account ownership changes, does not flag sudden divergence in publication cadence or geographic origin. A maintainer account silently transferred, an email reset against a lapsed domain, a session token replayed from a stolen browser profile - none of these surface in the resolver’s view. The gem is the gem. The signer of the artifact is, in practice, nobody - RubyGems gem signing exists but is not enforced and is rarely consumed.
What the attack produces in telemetry depends on the payload. The install-time vector - extconf.rb executing during bundle install - produces a child process under the build user. On a Linux CI runner that is typically Sysmon for Linux ProcessCreation events or auditd EXECVE records showing ruby or gcc invoking a downstream binary the workload does not normally invoke. Outbound connections to non-package-registry destinations during the install phase are the next signal - egress to Pastebin, to a raw GitHub gist, to an attacker-controlled webhook. Network telemetry from the runner correlates: CI build job, bundle install execution window, DNS resolution for a domain not on the gem mirror allow list.
The runtime vector - payload that activates on require, conditional on Rails.env.production or on a specific hostname pattern - is harder. The execution looks like the application running. The process tree is the application’s process tree. Detection moves to the application telemetry plane. Outbound connections from a Rails worker to addresses not in the egress allow list. Unexpected environment variable reads - ENV.each patterns at boot. EDR alert categories that fire are those keyed on process-to-process child spawns from the application process, on shell invocations from a Ruby parent, on memory regions allocated executable by an interpreter that does not normally JIT. SOC correlation rules anchored on bundle install activity correlated to subsequent egress within the same job ID catch the install-time class. They do not catch the dormant runtime class.
The gap is the dormant class. Gems that execute only under production telemetry-quiet conditions evade pre-deployment static scanning, evade install-time process monitoring, and surface only when production application traffic includes the trigger condition. Cooldown does not address this class beyond the temporal hope that someone else gets compromised first and triggers the public yank.
The technical reality post-feature is this. Bundler 2.6+ provides cooldown. Cooldown reduces - does not eliminate - the window where a freshly-published malicious gem reaches downstream builds. Lockfile checksums prevent post-resolution tampering of a known-good artifact, not publication of a known-bad one. Mandatory MFA on RubyGems covers the top of the distribution but not the long tail of low-download gems that nonetheless appear as transitive dependencies in production Gemfiles. Auto-update tooling that does not respect cooldown defeats the mitigation by design.
The systemic exposure is the resolver consuming a registry whose publication trust is account-credential-bound and whose artifact trust is signer-optional. Cooldown is one knob. It is the knob worth turning. It is not the knob that closes the class.
See also: NordVPN for tunneled traffic when operating outside controlled networks.
#ad Contains an affiliate link.
Keep Reading
portalMeta ships ADB-enabled firmware to deprecated Portals
Meta deprecated Portal devices with ADB enabled and patches stopped. Unpatched Android cameras and microphones now sit as permanent network exposure.
github-securityMegalodon hijacked 55,000 GitHub repos via token replay
Megalodon compromised 55,000+ GitHub repositories through PAT harvesting, pull_request_target abuse, and OAuth scope inheritance. Technical breakdown.
supply-chainYour valid credentials are the breach.
Technical analysis of a coordinated GitHub Actions workflow compromise across 5,561 repositories, with detection guidance for audit log and EDR telemetry.
Stay in the loop
New writing delivered when it's ready. No schedule, no spam.