DEV Community

Cover image for When to Skip Your Gem Cooldown
christine
christine

Posted on Originally published at christine-seeman.com

When to Skip Your Gem Cooldown

Wait two weeks before trusting a new gem, or patch the moment a fix ships? I've been going back and forth on that all week.

It's been a rough one. On November 4, Rails shipped 8.0.5.2 and 8.1.4.1 with fixes for 21 security advisories, one of them critical. Trilogy, the MySQL client gem behind one of Rails' database adapters, had fixed a critical SQL injection six days earlier and shipped a follow-up release the same day as Rails. Crass, a CSS parser that Rails pulls in through rails-html-sanitizer, picked up five advisories in ten days. Every one of those fixes was a brand-new release, and both apps I work on have a 14-day cooldown in their Gemfiles telling Bundler to skip brand-new releases.

The pressure to wait has been building all year! Supply chain attacks, where malicious code ships inside a dependency, kept coming: an agent swarm uploaded more than 3,000 spam gems to RubyGems.org from May to July, by JFrog's count (part one, part two), and in June Bundler added the cooldown setting so teams could wait out the next bad release. This week, waiting and patching pointed in opposite directions at the same time.

I don't have a settled answer. But here's where my team is and what this month showed us.

How We Ended Up With a 14-Day Wait

The two apps I work on got there in three steps.

  • December 2025: A 14-day cooldown was added to Dependabot, GitHub's dependency update bot, in one app, so Dependabot wouldn't make us a supply chain victim by accident. The same change grouped the updates, because the team was getting one pull request (PR) per gem (which when you have gems at scale is A LOT of PRs).
  • May 2026: the other app added the same 14-day Dependabot cooldown as part of hardening its supply chain.
  • June 3, 2026: RubyGems published Cool down before you install, and Bundler 4.0.13 shipped the cooldown setting. The same day, a teammate added source "https://rubygems.org", cooldown: 14 to both Gemfiles.

Both apps also hold npm packages back for 14 days with Yarn's npmMinimalAgeGate.

The Bundler setting matters most here, because it applies to people as well as the bot. A Dependabot cooldown only changes when Dependabot opens PRs. The Gemfile cooldown applies to every bundle update, including the one a developer runs by hand.

Why Both Rules Make Sense

A cooldown protects you from a malicious release of a gem you already depend on, and those tend to get caught fast. GitHub's post The case for a cooldown gives the numbers behind Dependabot's new 3-day default: in September 2025, hijacked releases of the npm packages chalk and debug were live for about two hours, and ua-parser-js and Ledger Connect Kit were each pulled within hours. Those are all npm examples. I didn't find the same kind of data for RubyGems.

The swarm was a different kind of attack. Those were new spam gems, not hijacked releases of gems people already use, and a cooldown does little against a gem nobody installs.

A security release pushes the other way. Once the advisory and patch are public, attackers can read the fix to find the bug. Staying on the old version gives them time to use it.

The two rules guard against different things, so most weeks they don't conflict. They collide when the only fix for a public vulnerability is a release younger than your cooldown. On November 4, that was Rails.

What We Did on November 4

We shipped the Rails patch the same day in both apps. In each one, a developer opened the upgrade PR by hand, and both merged by 9:15 that morning, Eastern time. Dependabot never opened a Rails PR, and I'll get to why.

Bundler's way past the Gemfile cooldown is an override for a single run:

bundle update rails --conservative --cooldown 0
Enter fullscreen mode Exit fullscreen mode

The RubyGems post describes --cooldown 0 for exactly this case, a disclosure that tells you to upgrade immediately. It overrides the Gemfile for that one command and leaves the policy in place for everyone else.

The PR in one app handled the override well. It listed the override as the first thing for reviewers to check and explained why: the fixes only existed in releases inside the 14-day window. It confirmed that each new gem's checksum matched the one on rubygems.org, and it left the Gemfile setting alone.

A good rule to go by

Routine updates wait out the cooldown. Updates for a published security advisory skip it.

Skipping it still means checking the release, because "urgent security update" is also a good disguise for a malicious one:

  • The advisory comes from the project's own channel, like the rubyonrails.org announcement or a GHSA (GitHub Security Advisory) in the project's own repo, not an issue comment or an email.
  • The checksums match. The Rails announcement published a checksum for every gem in the release.
  • The changes look like the fix. Skim the compare view between your version and the patch release, like v8.1.4...v8.1.4.1 for Rails on GitHub. The changes should be in the code the advisories describe.

Only skip it for the gem the advisory names, with --conservative, so the rest of the lockfile stays put.

Triage Before You Rush

Not all 21 Rails advisories needed a same-day patch in every app. CVSS (the 0-10 severity score) tells you how bad a bug is in general. Whether your app uses the affected code tells you how fast to move. One of our apps had no Active Storage attachments at all, so the critical advisory didn't apply there.

If you can't upgrade today, many advisories list workarounds that need no new gems: the ImageMagick policy for the critical Active Storage bug, turning off the video previewer, or forcing string encodings before they reach Trilogy.

Where the Bypass Leaks

This month turned up four cases the rule above doesn't cover cleanly.

  • Separate releases need their own bypass. --conservative keeps the lockfile change small, but it only updates Rails and what Rails requires. Trilogy shipped its fix on its own schedule, so a Rails upgrade never touches it.
  • Follow-up releases. Trilogy 2.13.3 came six days after the 2.13.2 fix, with a commit titled "Further harden encoding_for_charset" and no new advisory. Does the bypass cover a follow-up like that? I'd take it, but my own rule doesn't say so.
  • The gems Rails itself depends on. The Rails release required new versions of rails-html-sanitizer, loofah, and nokogiri, all published within the previous three days. The override covered all of them, not only the gem the advisory named.
  • The override has a side effect that lasts up to two weeks. Once the lockfile holds gems younger than the cooldown, a full bundle update fails with a cooldown error until they age out, around mid-November for us. It doesn't downgrade anything, but routine updates stall after every patch-now release.

What Dependabot Does on Its Own

On paper, Dependabot already follows the same rule. Its options reference says cooldown applies only to version updates, and security updates open right away. Both apps have Dependabot security updates turned on.

So why didn't Dependabot open a Rails PR? It couldn't. Dependabot alerts only come from advisories GitHub has reviewed into its global GitHub Advisory Database. As of November 9, none of the 21 Rails advisories are in the global database. Trilogy's advisory from October 29 isn't there either. The newest reviewed RubyGems entries in the database are still from October 29.

The built-in bypass waits on a review queue. For Rails, the same-day patch came from developers reading the announcement. Dependabot had nothing to act on.

When an advisory does get reviewed, the bypass works. One of the crass advisories was reviewed on October 28. In one app, Dependabot opened the security PR 54 minutes later, and it merged the next morning. Crass 1.0.8 was seven days old, inside the Gemfile's 14-day cooldown. In that app, the Gemfile cooldown didn't block Dependabot's security update.

Keep the Fast Path Fast

In my Rails post, an unrelated failure from Reek, a code smell checker, showed up in the middle of an urgent upgrade. A same-day patch only works if CI (the automated test run on every PR) is already green on an ordinary day.

Still Working It Out

This year brought an agent swarm on RubyGems, a 3-day default in Dependabot, a cooldown in Bundler, and 21 Rails advisories in one release. Here's what this month taught us:

  • A cooldown guards against hijacked releases, which tend to get caught within hours. A security release is the one update where waiting helps the attacker.
  • Routine updates wait out the cooldown. Advisory fixes skip it, after checking the source, the checksums, and the changes.
  • The bypass covers less than it looks like. Separate gems, follow-up releases, and the gems Rails pulls in each need their own decision.
  • Dependabot's security bypass only starts once GitHub reviews the advisory. For the November 4 Rails advisories, that still hasn't happened.
  • None of it is fast unless CI is already green.

The cooldown did its job, and we still shipped the Rails fix the same day. Where to draw the line between waiting and patching is each team's call. Make that call before the next advisory lands, while nobody is racing a deadline.

Top comments (0)