P.K. SHARMA

Cyber security intelligence, AI governance, practitioner analysis

Ruby core releases out-of-band updates after 3 Onigmo regex engine flaws enable RCE

The Ruby core maintenance team has issued coordinated out-of-band security updates across Ruby 4.0, 3.4, and 3.3 to remediate multiple memory corruption vulnerabilities in the Onigmo regular expression engine that expose web applications and CI/CD pipelines to remote code execution.

By Parminder Kumar Sharma · · 10 min read

Emergency out-of-band releases across three Ruby branches remediate critical Onigmo regex engine flaws

The Ruby core maintenance team has issued coordinated out-of-band security updates across all currently supported release branches to remediate three critical memory corruption vulnerabilities within Onigmo, the default regular expression engine embedded in the Ruby runtime. The releases, designated Ruby 4.0.9, Ruby 3.4.12, and Ruby 3.3.13, address severe parser and compiler flaws that permit unauthenticated remote code execution on servers and workstations evaluating untrusted regular expression patterns.

Discovered by security researcher Johan Carlsson (known as joaxcar), the vulnerabilities expose severe structural defects in how Onigmo parses complex pattern syntax and allocates heap memory for compiled regular expression bytecode. The most severe flaws involve a double-free condition triggered during abstract syntax tree (AST) error unwinding and multiple integer overflows during pattern size calculations, which result in undersized heap buffers and subsequent out-of-bounds memory writes.

The coordinated upstream security release arrived exactly 8 days after downstream enterprise platform GitLab published emergency patches on 15 October 2026 addressing the same Onigmo flaws within its own bundled Ruby environment. The disclosure underscores systemic architectural supply chain risks: Onigmo has served as Ruby's primary regular expression engine for 4989 days (13.66 years, derived) since replacing Oniguruma in Ruby 2.0.0 in February 2013, creating a ubiquitous attack surface across millions of enterprise web applications, CI/CD runners, and automation pipelines.

Architecture of the Ruby Onigmo regular expression compiler and memory attack surface

Figure 1: Complete compilation and memory exploitation lifecycle within Ruby Onigmo regex engine, tracing untrusted pattern ingestion through parser error unwind double-frees, compiler integer wrap-arounds, and heap control hijacking.

Patch velocity, runtime longevity, and technical parameters of the Onigmo vulnerability cluster

The upstream advisory addresses three primary Common Vulnerabilities and Exposures (CVE) assignments in the core language tracker, alongside companion downstream advisories that track related quantifier calculation defects. The vulnerabilities span both the lexical parsing phase and the bytecode emission phase of the regular expression compilation lifecycle.

Quantitative analysis of the disclosure timeline reveals an 8-day coordination window between downstream enterprise mitigation and upstream core distribution. GitLab remediated the flaws internally on 15 October 2026, followed by the upstream Ruby core team advisory on 23 October 2026. Because Onigmo is statically linked or built directly into standard Ruby language distributions, the vulnerabilities impact every deployment operating on unpatched Ruby runtimes.

Table 1: Quantitative telemetry, patch velocity, and vulnerability metrics for the Ruby Onigmo regular expression engine security release.

Vulnerability ParameterQuantified MetricTechnical and Operational Significance
Upstream Release Date23 October 2026Official coordinated patch release across Ruby 4.0, 3.4, and 3.3
Downstream GitLab Disclosure15 October 2026Emergency security release addressing bundled Onigmo flaws
Upstream Patch Response Gap8 DaysDerived delta between downstream vendor fix and core release
Onigmo Engine Integration24 February 2013Introduced in Ruby 2.0.0 as a modernised fork of Oniguruma
Engine Production Longevity4989 Days (13.66 Years)Derived duration Onigmo has served as default Ruby regex core
Supported Branches Remediated3 Active BranchesRuby 4.0.9, Ruby 3.4.12, and Ruby 3.3.13 point releases
Primary CVE Identifiers3 Core Language FlawsCVE-2026-89078, CVE-2026-93577, and CVE-2026-97229
Downstream Quantifier CVECVE-2026-110264Quantifier repeat integer overflow rated CVSS 10.0 in GitLab
Primary Defect Classes2 Memory Defect TypesAST node double-free and arithmetic integer overflow buffer overrun
Credited Vulnerability HunterJohan Carlsson (joaxcar)Independent security researcher credited across all three core flaws

Anatomy of CVE-2026-89078: The parser error unwind AST double-free vulnerability

The most complex memory management vulnerability resolved in this release cycle is CVE-2026-89078 (tracked in the upstream Ruby issue tracker as Bug #13332). The defect resides in Onigmo's recursive-descent pattern parser, specifically within the logic governing alternation constructs (represented in regular expression syntax by the vertical bar character |).

When a Ruby program compiles a regular expression containing multiple alternation branches, Onigmo dynamically allocates individual abstract syntax tree (AST) nodes on the process heap to represent each parsed sub-expression. If the first branch of an alternation compiles successfully, the parser records the node pointer within the parent tree structure. If the parser subsequently encounters an invalid syntax token or semantic constraint while parsing the second branch, it initiates an error cleanup routine.

In vulnerable versions of Onigmo, the error handling function invoked by the alternation parser freed the previously allocated AST node associated with the initial branch via a call to onig_node_free. However, the routine failed to nullify the pointer reference or detach the freed node from the enclosing syntax tree context. When control returned to the top-level onig_parse dispatcher, the failure status triggered a secondary, recursive tree-traversal cleanup that traversed the AST and invoked onig_node_free on the exact same memory address a second time.

In modern memory allocators such as glibc ptmalloc or jemalloc, a double-free condition corrupts heap metadata structures, including thread-local caching bins (tcache) or singly-linked fastbin freelists. By carefully crafting the size and structure of subsequent allocations, an attacker can manipulate heap pointer links to force the allocator to return an arbitrary memory address for future writes, turning an unhandled regex syntax error into a weaponised arbitrary code execution primitive.

Under glibc's tcache implementation, each thread maintains an array of singly-linked lists representing freed chunks of specific size classes up to 1024 bytes. When an application frees the same chunk pointer twice without an intervening allocation, the chunk's forward pointer (the fd pointer) is written into its own user payload area, creating a circular loop in the allocator's linked list. In older runtimes without hardened safe-linking pointer mangling (introduced in glibc 2.32), this loop enables an attacker to overwrite the pointer with an arbitrary target address, causing a subsequent malloc call in the Ruby process to return a pointer directly to sensitive process structures such as the global interpreter lock (GIL) state, Ruby method tables, or glibc hooks.

Forensic autopsy of AST node lifecycle and integer overflow memory corruption

Figure 2: Memory corruption mechanics of Onigmo regular expression vulnerabilities, illustrating the dangling pointer double-free in alternation tree unwinding and 32-bit integer wrapping during quantifier buffer allocation.

Anatomy of CVE-2026-93577 and CVE-2026-97229: Quantifier size wraps leading to heap under-allocations

While CVE-2026-89078 undermines memory safety during lexical parsing, the companion vulnerabilities CVE-2026-93577 and CVE-2026-97229 (tracked collectively under upstream Bug #19020) target the bytecode compilation phase where parsed AST nodes are translated into executable virtual machine opcodes.

When compiling regular expressions featuring quantifiers with large repetition bounds (such as patterns specifying high repetition counts or deeply nested quantifiers), Onigmo computes the required destination buffer size by multiplying the repeat count by the byte size of the underlying instruction sequence. In vulnerable versions, this calculation was executed using standard 32-bit signed or unsigned integer arithmetic without checking for arithmetic overflow.

By supplying a pattern with carefully calibrated large quantifier numbers, an attacker can trigger an integer wrap-around. For example, a calculation that mathematically requires several gigabytes of memory wraps around the integer threshold to produce a small positive integer, such as 64 bytes. The engine then calls malloc with this truncated size parameter, successfully allocating a tiny heap chunk.

Once the buffer is allocated, the compiler proceeds to execute its bytecode emission loop, iterating through the unscaled repetition count and writing compiled bytecode instructions directly into the destination buffer. Because the destination buffer is orders of magnitude smaller than the emitted bytecode volume, the compiler continuously writes opcodes out of bounds, stomping adjacent heap metadata, active Ruby object headers (RBasic structures), and function pointers in surrounding heap pages.

This class of vulnerability was highlighted earlier in downstream disclosures including CVE-2026-110264 (Bug #16801), where repeat quantifier ID calculations similarly overflowed. In downstream platforms like GitLab, which parse user-defined regular expressions in CI/CD pipeline job definitions, search queries, and issue filters, this flaw received a maximum CVSS v3.1 severity rating of 10.0 due to its unauthenticated remote exploitability.

The mechanics of the overflow expose fundamental design assumptions dating back to the engine's original C codebase. In 32-bit compilation models or when calculations are cast to 32-bit types, large repeat constants (such as 2 to the 31 minus 1) multiply against internal instruction descriptors to trigger integer truncation. Because Onigmo's bytecode compiler relies on an internal stack to manage sub-pattern matching states, corrupting the bytecode stream enables attackers to inject artificial jump opcodes (such as OP_JUMP or OP_PUSH), subverting the regular expression virtual machine into reading or executing arbitrary memory locations.

Blast radius across Rails applications, CI/CD runners, and RubyGems ecosystem

The security implications of these Onigmo vulnerabilities extend far beyond standalone Ruby utility scripts. In modern enterprise architectures, regular expressions are frequently compiled dynamically based on external inputs, establishing critical attack surfaces across web applications, application programming interface (API) gateways, and software development platforms.

A pervasive developer antipattern in the Ruby ecosystem is the dynamic construction of regular expressions using string interpolation. For instance, code constructs such as dynamic pattern interpolation or Regexp.new(params[:filter]) are widely employed in web search filters, routing engines, data validation pipelines, and text analysis services. Whenever untrusted user input is passed directly to these methods without strict character whitelist constraints, remote attackers can submit the malicious patterns that trigger Onigmo heap corruption.

Table 2: Common Ruby architectural attack surfaces and regular expression evaluation patterns susceptible to Onigmo memory corruption.

Architectural ComponentVulnerable Ruby API PatternOperational Exploit Exposure
Web Application Search FiltersRegexp.new(params[:query])Direct unauthenticated HTTP parameter compilation in public web forms
Dynamic Pattern Interpolation/#{user_input}/ =~ target_stringDynamic string interpolation compiling unvetted user regex tokens
CI/CD Pipeline Filter RulesRegexp.compile(ci_branch_rule)Evaluation of untrusted pipeline branch filters and commit message rules
Third-Party Gem ParsersRegexp.union(user_patterns)Aggregation of multiple untrusted regex rules into a composite pattern
API Gateway Content Routingrequest_path.match(route_regex)Dynamic route matching engines accepting external path-matching syntax
Log Analysis & SIEM PipelinesOnigmo bindings in Fluentd/LogstashParsing untrusted streaming log lines against user-configured regex rules

Crucially, software development tools that parse developer configuration files, repository hooks, or continuous integration definitions are equally exposed. An attacker contributing a malicious commit or pull request containing a crafted regular expression inside a configuration file can achieve remote code execution on the automated CI/CD runners that evaluate the rule during pre-merge validation.

Defense-in-depth engineering and runtime regex sanitisation protocols

Remediating the Onigmo vulnerability cluster requires an immediate, two-pronged engineering strategy combining binary runtime upgrades with defensive coding practices in application source code.

First, infrastructure operators must upgrade the Ruby runtime to version 4.0.9, 3.4.12, or 3.3.13 across all production servers, development containers, and build infrastructure. For organisations maintaining end-of-life Ruby installations (such as Ruby 3.2, 3.1, or 2.7), operating system vendors must be consulted for backported distribution packages, or codebases must be ported to supported Ruby versions immediately. Unsupported versions remain permanently vulnerable to both the AST double-free and quantifier integer overflow defects.

Second, application developers must audit their codebases to eliminate dynamic regular expression compilation based on untrusted input. Wherever user input must be matched literally against text, developers must wrap the input in Regexp.escape(user_input) before compiling, ensuring that meta-characters such as alternation pipes, parentheses, and repetition brackets are escaped into inert literal characters.

Where applications genuinely require end users to specify custom regular expressions (such as advanced search engines or custom alerting rules), engineers must implement strict defensive parsing wrappers. These wrappers should enforce an aggressive maximum character length (for example, rejecting patterns exceeding 256 characters) and utilise abstract syntax validation to prohibit nested quantifiers or extreme repetition bounds prior to passing the string to the Ruby runtime engine.

Sources

  1. PrimarySecurity Vulnerabilities in regular expression engine (Onigmo)Ruby Core Teamaccessed 2026-10-25
  2. Reported byGitLab Critical Security Release: Patching Onigmo Regular Expression Engine FlawsGitLabaccessed 2026-10-25

Share this briefing

Know someone who owns this problem? Send it to them.

Related briefings

The briefing, in your inbox

Practitioner analysis of cyber and AI security news. No vendor noise.

How often

Every new briefing in one email, at 7am, or at 7am, 12:30pm and 6pm. Nothing is sent when nothing is new. Unsubscribe any time.