The day after I wrote about PHP2Shell, Ruby posted regexp compilation fixes tied to four GitLab CVEs: CVE-2026-89078, CVE-2026-93577, CVE-2026-97229, and CVE-2026-110264. GitLab found that specially crafted regular expressions could corrupt memory while Ruby compiles them, and that this could be used for remote code execution on GitLab servers. GitLab rated two of them 10.0 out of 10 (CVSS 3.1), the two that needed no login.
Am I Affected?
You're affected if your app builds a regular expression from input you don't control. Per the Ruby advisory, that means passing it to Regexp.new, Regexp.union, or Regexp.compile, or interpolating it into a regexp literal like /#{input}/. If every regexp in your app was written by a developer, the advisory says you're not affected.
| Ruby series | Fixed in |
|---|---|
| 4.0 | 4.0.9 |
| 3.4 | 3.4.12 |
| 3.3 | 3.3.13 |
| 3.2 and older | No fix (end of life) |
Ruby 3.3 is in security maintenance and got these fixes as an exception, because GitLab assigned CVEs to the issues. Ruby 3.2 and older get no fix. Ruby 3.2.11 in March was the final 3.2 release, with no further security fixes, and Ruby recommends moving to 3.4 or 4.0.
The CVE IDs are GitLab's. Ruby hasn't requested its own CVEs for these yet and says it's still discussing whether to treat them as vulnerabilities, since Ruby has long considered compiling regexps from untrusted input unsafe.
Checking Your App
Ruby's version is often set in more than one place, so check what production actually runs. RUBY_VERSION in a Rails console on the server tells you. To find what you've pinned, check your version manager file (.ruby-version or .tool-versions), the ruby line in your Gemfile if there is one, your Docker base image tag, and any CI image you build separately.
To find places that compile regexps at runtime, a rough search is a good start:
grep -rnE 'Regexp\.(new|union|compile)|/[^/]*#\{' app lib
Expect some noise from the interpolation pattern. For each hit, the question is whether any part of the pattern comes from a user, a request param, or a database field users can edit.
What I Found in My Own App
I ran this check on a Rails app I work on. Ruby was set in three places, each needing a different fix:
- The version manager file pinned an older 4.0 patch release, so that needed a manual bump.
- The production Dockerfile used a floating tag like
ruby:4.0-alpine. A rebuild picks up 4.0.9 once the official image includes it, but it's worth confirming the patch version inside the image after the rebuild. - CI ran on a separately built image that only updates when someone reruns its build workflow. That one is easy to forget.
The search turned up three spots that build regexps from runtime strings. Patterns came from data import files and an admin form, and one used interpolation with values that looked internal, though I didn't trace every caller. None of them were reachable from a public API, so the risk was low, but anyone who can upload an import file controls those patterns. Upgrading Ruby is the fix either way.
Aside: The Upgrade Broke CI
Bumping to 4.0.9 the day it came out broke our CI in two ways. Jobs running in our CI Docker image failed because the build asked for a 4.0.9 image that couldn't exist until Docker Hub published ruby:4.0.9-alpine. Jobs using ruby/setup-ruby failed with "Unknown version 4.0.9", because each setup-ruby release only knows the Ruby versions that existed when it shipped, and ours was pinned to an older one. The fix was bumping the setup-ruby pin to v1.334.0, released that morning with 4.0.9 support, and keeping the image tag at 4.0 to rebuild once the official image caught up.
The lesson is the order: wait for the base image, bump setup-ruby, then change .tool-versions.
What's the Risk?
The bugs are in Onigmo, the regular expression engine built into Ruby. One is a double free (memory released twice, which can corrupt it) when parsing fails after an alternation (a | between options in a pattern). The others are integer overflows (a number too large for its type, wrapping around) in the size of the compiled pattern and in internal IDs for patterns with many repeats. Corrupted memory during compilation is what turns a bad pattern into code execution (Ruby advisory).
GitLab patched the Ruby it ships in 19.4.1, 19.4.2, and 19.5.1, with backports to older GitLab versions. GitLab.com and GitLab Dedicated are already patched. If you self-host GitLab, update GitLab itself. Its packages ship their own patched Ruby, and source installs also need the Ruby upgrade.
What to Do
Upgrade to Ruby 4.0.9, 3.4.12, or 3.3.13 or later, in every place you found above: version manager file,
Gemfile, Docker base image, and CI image.If you self-host GitLab, update to a patched GitLab release.
Look at any regexp built from user input and ask whether it needs to be a regexp at all. A plain string match is often enough.
If You Can't Upgrade Yet
The advisory's only mitigation is to avoid compiling regular expressions from untrusted input. It also rules out two things you might reach for:
-
Regexp.timeoutdoesn't help. It limits how long matching runs, and these bugs happen while the pattern compiles. - Limiting pattern length doesn't reliably help, because some of the bugs trigger with short patterns.
The advisory doesn't say whether escaping input with Regexp.escape is enough, so upgrading is the safe answer.
More Information
- Ruby advisory: Regexp compilation fixes related to GitLab's CVEs
- GitLab 19.4.1 patch release (CVE-2026-89078, CVE-2026-93577)
- GitLab 19.4.2 patch release (CVE-2026-97229)
- GitLab 19.5.1 patch release (CVE-2026-110264)
- Ruby fixes: #13332, #19020, #16801
- Regexp timeouts in the Ruby docs
Top comments (0)