
GitLab discovered four severe vulnerabilities in Ruby’s regular expression library. They’ve seen an attack in the wild from at least one of them. These are the most severe bugs found in ruby this year, and arguably the most impactful going back to CVE-2022-28738 in 2022. The impact could be remote code execution, similar to what we saw in PHP2Shell earlier this month. Fortunately Ruby applications are only vulnerable if they pass untrusted user input to the regular expression engine, unlike the PHP case which affected pretty much all apps.
The CVEs are:

Ruby has responded with patches for all of these under Ruby 3.3, 3.4, and 4.0. If you are on one of those versions of Ruby you should upgrade immediately. If you are running Ruby 3.2 or below you are affected by three of these and are not getting security patches. That means any application running Ruby 3.2 or below is now at serious risk and needs to prioritize upgrading Ruby.
The bugs are in regex compilation, which is what Ruby does behind the scenes when you write code like Regexp.new(".*"). An attacker can craft regex patterns which lead to an overflow that writes out to memory past the bounds of the buffer. The following examples prove whether your Ruby is affected.
# CVE-2026-110264
# vulnerable: returns a Regexp | patched: raises RegexpError ("too many range repeat")
Regexp.new("(?:foobar){0,100}" * 100_000)
# CVE-2026-110264
# vulnerable: returns a Regexp | patched: raises RegexpError
Regexp.new("(?:(?:foo)?|(?:bar)?)*" * 100_000)
# CVE-2026-93577/-97229
# the compiler tries to unroll an enormous program and hangs. (~20 bytes of pattern.)
# vulnerable: hangs (uninterruptible C loop) | patched: compiles immediately
Regexp.new("(?:.{90000,}){90000}")
If you are running an unsupported version of Ruby and can’t upgrade now, you should put in defense measures against user-controlled regexp inputs. The vulnerabilities are anywhere that an attacker could force your application to compile user-submitted data as a regexp pattern. For example Regexp.new(params[:user_regexp]) would be vulnerable.
You can run these greps to find possible affected sites and then verify whether anything dynamic is being passed in to the regex compilation.
# Regexp construction
grep -rnE 'Regexp\.(new|compile|union)' --include='*.rb' .
# Interpolation inside a regexp literal: /.../#{ ... }/
grep -rnE '/[^/]*#\{' --include='*.rb' .
# Regexp.escape is NOT a safeguard here — escaping still produces a pattern
# that compiles; these bugs are about pattern SIZE/structure, not metacharacters.
grep -rnE 'Regexp\.escape' --include='*.rb' .
There is no way to make this safe on user-controlled regex under Ruby 3.2 or below. You need to disallow user provided input to that compiler until you can upgrade to a patched ruby. Traditional countermeasures (Regexp.timeout or length limits) don’t help. Regexp.timeout applies to regex matching, where the bug here is in compilation, and the examples above demonstrate that we can trigger the behavior with short expression patterns.
We can go further in demonstrating vulnerability without sharing a full POC if we incorporate the AddressSanitizer detector (which uses the ASan project). This is a runtime detector of various kinds of memory errors that will crash ruby and print a stacktrace under some dangerous conditions.
To run ruby with ASan enabled we need to compile it from scratch. I’ve put an example Docker image up in a gist here. Compile say ruby 3.4.11 with that Dockerfile and run this:
docker run -it ruby-asan:3.4.11 bash
root@d604d6a192d4:/src# irb
irb(main):001> Regexp.new("|{1000000}")
=================================================================
==9==ERROR: AddressSanitizer: heap-use-after-free on address 0x5060006c4ac0 at pc 0x7c5d99f76b1f bp 0x7ffea9511bd0 sp 0x7ffea9511bc8
READ of size 4 at 0x5060006c4ac0 thread T0
The stack trace in bold shows the heap-use-after-free condition being triggered.
You can run the same code on a patched version to verify the fix:
docker run -it ruby-asan:4.0.9 bash
root@d604d6a192d4:/src# irb
irb(main):001> Regexp.new("|{1000000}")
(irb):1:in 'Regexp#initialize': too big number for repeat range: /|{1000000}/ (RegexpError)
None of this is a working exploit, but it’s enough to prove one might be possible. You should upgrade Ruby immediately.




