CISA added CVE-2026-97229 to its Known Exploited Vulnerabilities list on October 29. It is a CVSS 10.0 bug in how GitLab handles regular expressions in CI/CD configuration, and federal agencies have until November 1 to fix it. GitLab's own packages have had the fix since October 12. But the bug lives in Onigmo, the regex engine inside Ruby, and Alpine Linux spent two weeks learning that an upgraded GitLab on a stock Ruby is still an unpatched server.
That second part is the story. The first part is a press release.
What the bug is
A GitLab CI config can contain regular expressions. Rules, only/except patterns, that kind of thing. GitLab validates them, compiles them, and later evaluates them against repository paths and branch names. The validation step compiles the pattern in a compact US-ASCII form. When the pattern is later matched against a UTF-8 string, Onigmo recompiles it for the new encoding, after validation has finished.
Rapid7's analysis traced the fault to the program size calculation in that second compile. An integer overflow produces a compiled program with invalid instructions. From there the attacker runs Onigmo VM operations inside the Ruby process and ends with an OS command running as the git user. Rapid7 reproduced it on the official 19.4.1 CE image with ASLR on and published a proof of concept. The same input did nothing on 19.4.2.
GitLab scored it as unauthenticated, network, no user interaction. Rapid7 pushed back on the unauthenticated part. The working exploit needs to commit a .gitlab-ci.yml to a public project whose repository path contains a UTF-8 character. On an instance that lets new users self-register and create public projects, that is no barrier at all. On a locked-down instance it is a real one. Your signup policy decides which score applies to you.
Johan Carlsson, who goes by joaxcar on HackerOne, found it through GitLab's bug bounty. GitLab shipped fixes in 19.4.2, 19.3.5 and 19.2.8 on October 12. It first listed 19.3.4 as a fixed version and corrected that to 19.3.5 later. Remember that detail.
Where the fix went
GitLab does not own Onigmo. Ruby does. GitLab found four regex compiler bugs in all, assigned four CVEs, and patched the Ruby it bundles in Omnibus packages, the official Docker images and the Helm chart. Then it reported the bugs upstream.
Ruby released 3.3.13, 3.4.12 and 4.0.9 on October 23, eleven days after GitLab's fix shipped. Ruby's release post says the bugs reach only code that compiles a regex from a string an attacker controls: Regexp.new, Regexp.union, Regexp.compile, or interpolation into a literal. Regexp.timeout does not help. Limiting pattern length does not help either, since some of the triggering patterns are short. Ruby 3.3 is in security maintenance and got the fix as an exception. Ruby 3.2 is end of life and gets nothing.
Ruby has not requested its own CVEs for these fixes. The release post says the team will discuss whether memory corruption during regex compilation counts as a vulnerability, which is an odd debate to have given that Ruby issued CVE-2022-28738 and CVE-2024-27282 for the same class of bug. Until it is settled, the only identifiers your scanner can match are GitLab's. That is how an interpreter bug stays invisible to everyone who runs Ruby and does not run GitLab.
So for eleven days the fix existed only inside GitLab's packages. If you ran GitLab from source, or from a community image that installs the distro's Ruby, you had an interpreter with a known remote code execution bug and a GitLab version number that said you were fine.
Alpine's two weeks
Alpine Linux runs its own GitLab for aports, the repository every Alpine package is built from. Their incident report, published October 28, is the most candid timeline I have read this year.
October 13: Alpine upgraded to 19.3.4, the version GitLab had first listed as fixed. It wasn't.
October 20: a newly registered account started probing. October 21: the account submitted crafted CI configurations and crashed GitLab worker processes eight times. Users saw 502 errors and failed CI jobs. In four of the eight crashes, Alpine says, the attacker got partway through the exploit before failing at the next step. The attacker also pulled Alpine's GitLab container image, which Alpine reads as tuning the exploit against their exact build. Alpine published four stable point releases the same day.
October 22: Alpine upgraded to 19.3.6. That did nothing, because their image uses the distro's Ruby and the fix was a patch GitLab applied to its own embedded interpreter. October 23: Alpine blocked the account, and Ruby shipped the upstream fix. October 25 and 26: the attacker came back and failed. October 26: Alpine found the server still vulnerable.
October 27 and 28: GitLab closed to everyone but developers and build servers, was rebuilt from scratch, every password was reset, and GitLab's secret keys were replaced. October 29: it reopened on 19.3.7.
Alpine's conclusion: "We have found no evidence that the attacker ran code on the server, but we cannot rule it out." The reason they cannot rule it out is the part I would put on a slide. A successful exploit crashes nothing and leaves nothing in the web logs. Some background job logs from the attack window are gone. Outbound connections were not logged, and the hosting provider keeps nothing either. So they checked what they could. Commits from October 20 to 22 were compared against a developer's clone and all 45 builders. Packages built October 20 through 24 on every architecture matched those commits. The keys that sign packages and releases were never on the GitLab server, so even a full compromise could not have forged a release.
Checking your own install
If you run GitLab from Omnibus, the official Docker image or the Helm chart, and you are on 19.4.2, 19.3.5, 19.2.8 or later, you are done with this one. GitLab closed a second Onigmo overflow, CVE-2026-110264, in its October 21 releases, so you may as well take those.
If you run GitLab from source, from a distro package, or from a community container, the GitLab version tells you nothing. Run ruby -v as the git user that runs Puma and Sidekiq. You want 3.3.13, 3.4.12 or 4.0.9. Anything older, including a current GitLab on Ruby 3.2, is exposed. Alpine's own alpinelinux/gitlab:19.3.6 tag was vulnerable in every pull before October 27 and has to be pulled again.
If you run any Ruby application that builds a regex from user input, you have the same bug with no CVE pointed at you. Grep for Regexp.new, Regexp.union and interpolated regex literals. Rails apps that let users define filters or search patterns are the common case.
Shadowserver counts close to 2,800 GitLab Community Edition instances reachable from the internet, per BleepingComputer. Some fraction of those are patched. Some fraction of the patched ones are patched the way Alpine was patched on October 22.
Alpine listed four changes it is making, and none of them is exotic:
- Patch critical GitLab releases faster.
- Check whether a GitLab release carries a patch to a bundled component, and apply that component fix separately.
- Log outbound and database connections, and keep them longer than 14 days.
- Sign release tags so a release can be verified without trusting the forge.
The outbound logging is the one I'd do first. Alpine couldn't prove a negative because the data to prove it was never collected. That is a cheap fix to make before the next CVSS 10, and there will be a next one. Two of the four bugs GitLab reported to Ruby this month were integer overflows in the same compiler.