Ruby Weekly
Specially crafted patterns can hang or corrupt memory during regex compilation. Fixed in 4.0.9, 3.4.12, and 3.3.13.

#​823 — October 23, 2026

Read on the Web

Ruby Weekly

Ruby regexp security fixes
Who needs to update?

It's very rare I'll do an out-of-band issue of Ruby Weekly but after digging into today's security releases of CRuby, I felt it was prudent to spread the word.

Ruby 4.0.9, 3.4.12, and 3.3.13 have all been released today with fixes for regexp bugs behind four GitLab-assigned CVEs. If you can update, do so. But I'll explain what the issues are below and you can determine if they affect you.

Takashi Kokubun's official advisory has the full story, if you want to go direct to the most official source.

Note: These bugs are specific to CRuby's Onigmo engine. JRuby and TruffleRuby use different regex engines and aren't affected by these fixes.

What are the bugs?

There were three bugs in Onigmo, Ruby's regular expression engine, that could corrupt memory while a regex pattern is being compiled:

  1. A double free when parsing a pattern fails after an alternation. Ruby 4.0 has had this fix since 4.0.0.
  2. An integer overflow in the size of a compiled pattern, first fixed in 4.0.8 – released yesterday.
  3. An overflow of internal IDs in patterns with many repeats, fixed in 4.0.9.

So if you moved to 4.0.8, which I featured yesterday, you need one more bump.

GitLab found these bugs could enable remote code execution on GitLab servers, including attacks that require no login. It assigned four CVEs rated Critical (CVSS 9.9 or 10.0) and patched the Ruby it ships. Ruby hasn't requested separate CVEs for these fixes so far; its advisory asks users to track them under GitLab's identifiers.

Is your code affected?

You're exposed if your application (or a dependency, alas) compiles regex patterns whose structure a third party can control. For example:

  • Regexp.new or Regexp.compile called on user input.
  • Interpolating input into a regex literal, like /#{params[:q]}/. Interpolation doesn't escape, so the user can supply a pattern.

Think regex-powered search boxes, user-defined validation rules, or filters in CI and webhook tools. If every regex in your stack is written by you/your team, you're in a better position.

Two things that won't help: Regexp.timeout, since the damage happens during compilation before matching starts, and limits on pattern length, because some of the bugs can be triggered by short patterns. Before the compiled-size fix, for instance, Regexp.new("(?:.{90000,}){90000}") was enough to lock up the process.

What should you do?

  1. Upgrade to Ruby 4.0.9, 3.4.12 or 3.3.13. (Ruby 3.3 normally gets only vulnerability fixes now; the core team backported these as an exception, since GitLab, not Ruby, is the one treating them as CVEs.)

  2. Find the risky spots in your code by looking for Regexp.new, Regexp.compile, Regexp.union and /#{ constructions, and checking where their input comes from.

  3. Can't upgrade yet? The official best practice is to avoid compiling regexes from untrusted input at all. How you do that is up to you: Regexp.escape turns user input into a literal-only pattern, and a plain substring match (e.g. include?) can be enough for many situations.

  4. On Ruby 3.2 or older? Older versions are end-of-life and won't get official fixes, so step 3 is your main option for now.

I'll be back next Thursday with, I hope, a regular issue… 😅

___
Peter Cooper, editor of Ruby Weekly

Issue 822 #823