The Ruby regexp vulnerabilities of October 2026 began as a series of GitLab security incidents. GitLab found that specially crafted regular expressions could corrupt memory while Ruby compiled them, and that attackers could turn this into code execution on GitLab servers. GitLab assigned four CVEs, two of them CVSS 10.0 and exploitable without logging in, and patched its own builds. The Ruby core team then released Ruby 4.0.9, 3.4.12, and 3.3.13 on October 23, 2026 to fix the underlying bugs in Onigmo, Ruby’s regular expression engine, for every Ruby application.
This article was created with AI assistance. Facts were checked against the official ruby-lang.org announcement and GitLab’s patch release notes on October 23, 2026. Confirm details in those advisories before acting.
TL;DR: what to install
| If you run | Upgrade to | Notes |
|---|---|---|
| Ruby 4.0.x | 4.0.9 | Released October 23, 2026 |
| Ruby 3.4.x | 3.4.12 | Released October 23, 2026 |
| Ruby 3.3.x | 3.3.13 | Released October 23, 2026 |
| Ruby 3.2 or older | Move to 3.3, 3.4, or 4.0 | End of life: no fixed release |
| GitLab self-managed (CE/EE) | 19.5.1, 19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10, or 18.11.13 | Every version from 7.0 is affected by CVE-2026-110264 |
| GitLab.com and GitLab Dedicated | No action | Patched by GitLab before disclosure |
Timeline: four GitLab CVEs, one Ruby fix
| Date (2026) | Release | CVE | CVSS | Authentication |
|---|---|---|---|---|
| September 23 | GitLab 19.4.1, 19.3.3, 19.2.7 | CVE-2026-89078: double free in regular expression parser | 9.9 | Authenticated user |
| September 23 | GitLab 19.4.1, 19.3.3, 19.2.7 | CVE-2026-93577: integer overflow in regular expression compiler | 9.9 | Authenticated user |
| October 12 | GitLab 19.4.2, 19.3.5, 19.2.8 | CVE-2026-97229: integer overflow in CI/CD regular expression compiler | 10.0 | None |
| October 21 | GitLab 19.5.1, 19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10, 18.11.13 | CVE-2026-110264: integer overflow in regular expression compiler | 10.0 | None |
| October 23 | Ruby 4.0.9, 3.4.12, 3.3.13 | Fixes the Onigmo bugs behind all four CVEs | — | — |
GitLab’s affected-version ranges for CVE-2026-110264 include 19.4.2, the October 12 release. Servers patched for CVE-2026-97229 were therefore still exposed until they installed the October 21 release. GitLab released threat detections for self-managed customers, named “Onigmo native worker crash” and “Org mode render error burst”, and offered no workaround other than upgrading.
Separately, on August 27, 2026, Ruby disclosed CVE-2026-80212 and CVE-2026-80213 in the bundled resolv gem. If you have not updated resolv since then, do it in the same change.
The root cause: three bugs in Onigmo
According to the Ruby announcement, the CVEs trace back to three bugs in Onigmo:
- A double free when parsing fails after an alternation.
- An integer overflow in the size of the compiled pattern.
- An overflow of internal pattern IDs when a pattern contains many repeats.
The critical condition is that the bugs are reached only when an application compiles a regular expression from a string an attacker controls, through Regexp.new, Regexp.compile, Regexp.union, or interpolation such as /#{input}/. Applications that only use regular expressions written by their own developers are not affected by these bugs.
Reported analysis also notes that Regexp.timeout and pattern-length limits do not stop them. Timeouts protect against slow matching, not memory corruption during compilation, and some of the bugs can be triggered with short patterns.
Lessons from the GitLab incidents
- User-supplied patterns are everywhere in developer platforms. CI/CD rules, branch and push rules, search filters, code owners, file previews, and markup renderers all accept patterns or pass content through regex-heavy parsers. The more configurable your product, the more of these paths exist.
- Authenticated bugs become unauthenticated bugs. The September CVEs required a logged-in user. The October ones did not, because the same engine bug was reachable through paths that anyone who could reach the server could trigger.
- Fixing a call site is not fixing the bug. The October 12 patch closed one path, and a sibling bug in the same engine needed another emergency release nine days later. When the root cause is in a shared runtime component, patch the runtime and review every call site.
- Bundled runtimes need their own updates. GitLab ships its own Ruby, so upgrading the system Ruby on a GitLab server does not fix GitLab. The same applies to any appliance or image that vendors an interpreter.
- Managed services move first. GitLab.com and Dedicated were patched before disclosure, while self-managed customers had to act. If you self-host, monitor vendor advisories as closely as your own code.
Is your Ruby application affected?
Search your application and its gems for regular expressions built from runtime data:
# Application code
grep -rnE 'Regexp\.(new|compile|union)|/[^/]*#\{' app lib config
# Installed gems in the bundle
grep -rnE 'Regexp\.(new|compile|union)' $(bundle list --paths) 2>/dev/null | grep -v /spec/ | head -50
Then trace each match back to its input. Typical risky patterns in Rails and other Ruby apps:
Regexp.new(params[:q])in search, filter, or “advanced query” endpoints.- Admin or tenant settings that store patterns: routing rules, allowlists, redaction rules, alert conditions, webhook filters.
Regexp.union(list)where the list comes from users or a database.- Markup, templating, or import features that build patterns from document content.
A quick test on staging: send a lone ( or [ to a suspect parameter. If the response is a 500 error or a RegexpError message, the parameter is being compiled as a regular expression.
If nothing in your code or gems compiles untrusted patterns, these bugs are not reachable in your application. Upgrade anyway: dependencies change, and the fix is a routine patch release.
Interim mitigations
- Stop compiling untrusted patterns. This is the Ruby team’s recommendation if you cannot upgrade.
- Treat user input as literal text when users only need substring search: use
String#include?,start_with?, orRegexp.new(Regexp.escape(input)), which removes the regex syntax these bugs need. - Use a different engine for real pattern features. If users genuinely need regular expressions, the
re2gem uses Google’s RE2 engine instead of Onigmo and is designed for untrusted patterns. - Restrict who can save patterns to trusted administrators while you upgrade.
- For self-managed GitLab: restrict network access to the web UI (VPN or allow lists), enable GitLab’s threat detections, and watch for unusual child processes from GitLab services.
- Do not rely on
Regexp.timeoutor length limits for these bugs.
Ruby upgrade paths by setup
Version managers
Update the definitions first, then install the patched version and update .ruby-version:
# rbenv (update ruby-build so the new versions are known)
git -C "$(rbenv root)"/plugins/ruby-build pull # or: brew upgrade ruby-build
rbenv install 3.4.12 && rbenv global 3.4.12
# asdf / mise
asdf install ruby 3.4.12 # mise: mise install [email protected]
# RVM
rvm get stable && rvm install 3.4.12
If your Gemfile declares ruby "3.4.11", update it, run bundle install, and commit the updated RUBY VERSION in Gemfile.lock. Native extension gems do not need code changes for a patch release within the same Ruby branch.
Docker images
Official ruby images publish tags such as ruby:3.4.12, ruby:3.4-slim, and ruby:4.0-alpine. Rebuild with docker build --pull, update pinned tags or digests in every build stage, and redeploy:
docker build --pull --no-cache -t registry.example.com/app:ruby-sec-2026-10 .
docker run --rm registry.example.com/app:ruby-sec-2026-10 ruby -v # expect 3.4.12, 4.0.9, or 3.3.13
Distribution packages
Debian, Ubuntu, RHEL, and Alpine package specific Ruby branches and backport fixes, so the version string may not match upstream. Follow your vendor’s advisory (DSA, USN, RHSA, Alpine secdb) for the fixed package release.
PaaS and buildpacks
Platforms such as Heroku select Ruby from your Gemfile and Gemfile.lock. Update the declared version and redeploy once the platform publishes it. On other platforms, update the runtime setting or base image and redeploy.
Self-managed GitLab
Upgrade GitLab itself, not the system Ruby. Omnibus (Linux package), Docker, and Helm installations bundle their own Ruby. Install 19.5.1 or the fixed release for your minor version (19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10, or 18.11.13), following GitLab’s upgrade path tool if you are several versions behind. GitLab notes that single-node instances have downtime during migrations, while multi-node deployments can follow the zero-downtime upgrade procedure.
CI and developer machines
Update ruby/setup-ruby versions or .ruby-version files used in CI, rebuild internal CI images, and upgrade developer machines with the same version manager commands.
Zero-downtime rollout for Ruby apps
- Puma: a phased restart replaces workers but keeps the master process, which still runs the old Ruby. For a Ruby upgrade, roll new instances or containers behind your load balancer, or use a full hot restart that re-executes the master with the new binary.
- Sidekiq and other job processors: send
TSTPto stop fetching new jobs, wait for in-flight jobs, then stop and start the process on the new Ruby. - Unicorn:
USR2re-executes the master with the new binary; sendQUITto the old master after the new workers are healthy. - Kubernetes: rolling updates with readiness probes,
maxUnavailable: 0, a PodDisruptionBudget, and gracefulSIGTERMhandling. Include CronJobs and worker Deployments. - Canary first, and keep the previous image digest or Ruby install available for rollback.
Verify the upgrade
- Run
ruby -von every host and image, and checkRUBY_VERSIONfrom inside the running app (for example in a Rails console or health endpoint). - Restart every long-running Ruby process (web servers, Sidekiq, schedulers, consoles) and confirm start times are after the upgrade.
- For GitLab, run
sudo gitlab-rake gitlab:env:infoor check Admin → Overview to confirm the fixed version. - Run
bundle update resolvif needed andbundle audit(from the bundler-audit gem) for other gem advisories. - Re-run your test suite and smoke tests, then rescan your inventory so it reflects the new versions.
How DAST tools help you catch issues like this sooner
No scanner can predict an undisclosed bug in a language runtime, and upgrading Ruby is the only fix for these CVEs. The GitLab incidents show what makes a runtime bug dangerous, though: an application path that feeds attacker-controlled input into it. Dynamic application security testing exercises your API from the outside with hostile input and shows you how it fails.
DastPilot scans your APIs from an OpenAPI spec or Postman collection, as every role you configure. Checks that matter for Ruby and Rails applications:
- Malformed-input probes on every documented parameter, flagging unhandled
500errors. A parameter that crashes on unexpected input often reaches a parser, compiler, or interpreter it should not. - Verbose error leakage: stack traces and file paths in responses, which reveal framework internals and the exact code paths attackers want.
- Stack fingerprinting: flags headers such as
X-Runtime(added by Rack and Rails),X-Powered-By, andServerthat tell attackers which runtime to target. - Injection: server-side template injection, command, SQL, and NoSQL injection, and path traversal.
- Authorization: BOLA, BFLA, and authentication checks. As GitLab’s September CVEs show, a flaw reachable by any authenticated user is only as contained as your access controls.
- Regression tracking: each scan is compared with the last, so a weakness that returns after an emergency deploy is flagged as reopened.
Run scans on a schedule or in your CI/CD pipeline, and rescan staging after a runtime upgrade. DAST complements patching and code review: pair it with the code search above and with dependency scanning to find every place untrusted input meets a risky API. The same approach applies to the other runtime emergencies this month: see our guides to the Node.js October 2026 release, nginx 2026 vulnerabilities, and the critical PHP release.
Frequently asked questions
Which Ruby versions fix the GitLab regexp CVEs?
Ruby 4.0.9, 3.4.12, and 3.3.13, released on October 23, 2026, fix the Onigmo bugs behind CVE-2026-89078, CVE-2026-93577, CVE-2026-97229, and CVE-2026-110264. Ruby 3.2 and older are end of life and have no fixed release.
Is my Ruby application affected by CVE-2026-110264?
Only if it compiles regular expressions from attacker-controlled strings, for example with Regexp.new, Regexp.compile, Regexp.union, or /#{input}/ interpolation. Applications that only use regular expressions written by their developers are not affected by these bugs, but should still upgrade.
What is CVE-2026-110264?
CVE-2026-110264 is a CVSS 10.0 integer overflow in the regular expression compiler that allows an unauthenticated attacker to execute code on self-managed GitLab servers. It affects GitLab CE/EE from 7.0 and is fixed in GitLab 19.5.1, 19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10, and 18.11.13.
Does Regexp.timeout protect against these Ruby vulnerabilities?
No. Regexp.timeout limits slow matching, while these bugs corrupt memory when a pattern is compiled. Length limits are also unreliable because some of the bugs can be triggered by short patterns. Upgrade Ruby, or stop compiling untrusted patterns.
Do I need to upgrade system Ruby on a GitLab server?
Upgrading system Ruby does not fix GitLab, because GitLab Linux packages, Docker images, and Helm charts bundle their own Ruby. Upgrade GitLab itself to a fixed release. GitLab.com and GitLab Dedicated were already patched.
Can a DAST scanner find Ruby regexp vulnerabilities?
A DAST scanner cannot identify which Ruby CVEs apply to you. DAST tools such as DastPilot send malformed input to every documented parameter and flag unhandled server errors, verbose stack traces, stack fingerprint headers, injection, and authorization gaps, which help you find risky input paths before attackers do.
Find the input paths attackers chain with runtime bugs
DastPilot flags unhandled errors, stack trace leaks, fingerprint headers, injection, and authorization flaws in your Ruby APIs, and rechecks them on every scan. 30-day free trial, no credit card required.
Start Free Trial