Find the GitLab you forgot
Continuous attack-surface discovery works from certificate transparency, DNS history and live probing, so the pilot instance and the acquired company’s server turn up alongside the one in your inventory.
Vulnerability advisory · GitLab
GitLab’s ad-hoc critical patch release of 21 October 2026 fixes a CVSS 10.0 flaw that, under certain conditions, lets an unauthenticated user run code on a self-managed GitLab server. Every version from 7.0 onward is affected, GitLab backported the fix to seven release lines — and an instance patched only nine days earlier, for a closely related bug, is still exposed.
On 21 October 2026 GitLab published versions 19.5.1, 19.4.3 and 19.3.6 for Community and Enterprise Edition, carrying twelve security fixes, and backported the critical one to 19.2.9, 19.1.9, 19.0.10 and 18.11.13 — four lines that would normally be outside its security maintenance window.
The CVE record describes the flaw in a single sentence: an issue “affecting all versions from 7.0 before 18.11.13, 19.0 before 19.0.10, 19.1 before 19.1.9, 19.2 before 19.2.9, 19.3 before 19.3.6, 19.4 before 19.4.3, and 19.5 before 19.5.1 that, under certain conditions, could have allowed an unauthenticated user to execute arbitrary code on the GitLab server due to integer overflow when compiling a specially crafted regular expression.”
GitLab.com was already running the fixed version when the advisory went out, and GitLab Dedicated tenants on 19.3.5-internal0 / 19.4.2-internal0 or later need no action. Every self-managed instance is its owner’s responsibility — and with the hosted platform patched, self-managed servers are what is left to attack.
The release landed on the same day as critical fixes from PHP and Node.js, four days after the eMudhra CA compromise was reported.
GitLab classifies the bug as CWE-190, integer overflow. Ruby’s security team published the underlying detail on 23 October: the defect is in Onigmo, the regular-expression engine built into Ruby, and is an “overflow of internal IDs in a pattern with many repeats”. A counter wraps around while a pattern is compiled, and memory is corrupted when the pattern is later used — which is how an arithmetic bug becomes code execution.
GitLab ships its own patched Ruby inside its packages, so the fix arrives through the GitLab upgrade, not through your operating system’s Ruby. Ruby has released 4.0.9, 3.4.12 and 3.3.13 with the same fixes, but those matter to GitLab only if you build it from source against a system Ruby.
GitLab’s published detection guidance identifies where the vulnerable code is reached: its rendering of Org-mode (.org) markup files, where a regular expression is built from content inside the file. The same guidance says the unauthenticated path needs a public .org file that GitLab renders — which is why instances with public projects, or open self-registration, are the most exposed. GitLab has not published how an attacker without an account places such a file, and neither do we; “under certain conditions” is the honest summary.
| CVE | Fixed in | CVSS | What it was |
|---|---|---|---|
| CVE-2026-89078 | 19.4.1 (23 September) | — | Double free in the regular-expression parser |
| CVE-2026-93577 | 19.4.1 / 19.3.3 / 19.2.7 (23 September) | 9.9 | Authenticated code execution through a regex in CI/CD configuration |
| CVE-2026-97229 | 19.4.2 / 19.3.5 / 19.2.8 (12 October) | 10.0 | Unauthenticated code execution through a regex in CI/CD configuration |
| CVE-2026-110264 | 19.5.1 and backports (21 October) | 10.0 | Unauthenticated code execution — a different Onigmo bug, reached through Org-mode rendering |
The practical consequence: an instance patched on 12 October for CVE-2026-97229 is still vulnerable to CVE-2026-110264. The earlier fix corrected a different overflow, and the 21 October release is needed on top of it.
Ruby’s advisory is precise about who else is affected: the bugs “are reached only when an application compiles a regular expression from a string that an attacker controls”, through Regexp.new, Regexp.union, Regexp.compile or interpolation such as /#{input}/. Applications that only use patterns written by their developers are not affected. Two warnings in the same advisory are worth repeating: Regexp.timeout “does not protect against these bugs”, and limiting pattern length does not reliably help either. Ruby has not requested its own CVE IDs and asks scanners to track GitLab’s.
| Your release line | Upgrade to | What the release contains |
|---|---|---|
| 19.5.x | 19.5.1 | All twelve fixes |
| 19.4.x | 19.4.3 | All twelve fixes |
| 19.3.x | 19.3.6 | All twelve fixes |
| 19.2.x | 19.2.9 | Backport of CVE-2026-110264 |
| 19.1.x | 19.1.9 | Backport of CVE-2026-110264 |
| 19.0.x | 19.0.10 | Backport of CVE-2026-110264 |
| 18.11.x | 18.11.13 | Backport of CVE-2026-110264 |
| 18.10 and older, back to 7.0 | No patch on your line | Upgrade along GitLab’s upgrade path, through its required stops, to a fixed release |
| CVE | Severity | Issue (as titled by GitLab) | CVSS |
|---|---|---|---|
| CVE-2026-15723 | High | Improper authentication in OmniAuth-to-LDAP auto-linking email lookup | 8.2 |
| CVE-2026-112212 | High | Cache poisoning in OAuth/OIDC discovery endpoints | 7.5 |
| CVE-2026-12664 | Medium | Improper access control in the GraphQL work item email address field | 6.8 |
| CVE-2026-16255 | Medium | Incomplete enforcement of the instance-wide SAML/LDAP membership lock (EE) | 5.9 |
| CVE-2026-105777 | Medium | Internal credential exposure in internal response headers | 4.3 |
| CVE-2026-13319 | Medium | Authorization bypass through a user-controlled key in the group milestones API | 4.3 |
| CVE-2026-112378 | Medium | Use of a less trusted source in the AI Gateway feature-enablement header (EE) | 4.3 |
| CVE-2026-105711 | Low | Cached sensitive information in merge request title rendering | 3.5 |
| CVE-2026-14288 | Low | Improper access control in merge request approval policy enforcement (EE) | 3.1 |
| CVE-2026-112326 | Low | Improper cleanup on a thrown exception in security findings (EE) | 3.1 |
| CVE-2026-103515 | Low | Improper access control in group Duo admin-lock enforcement for Amazon Q settings (EE) | 2.7 |
The first thing to know is what you cannot do: read a self-managed GitLab’s version anonymously. The /help page shows the version only to signed-in users, and /api/v4/version returns 401 without a token. An external scan can confirm that GitLab is running and reachable; it cannot honestly tell you the patch level. That answer needs an account, a token or access to the server.
# With any user's personal access token (read_api scope is enough)
curl -s --header "PRIVATE-TOKEN: $TOKEN" https://gitlab.example.com/api/v4/version
# On the server — Linux package (Omnibus) installs
sudo gitlab-rake gitlab:env:info | grep -A3 'GitLab information'
cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
dpkg -l gitlab-ee gitlab-ce 2>/dev/null | awk '/^ii/{print $2, $3}'
rpm -q gitlab-ee gitlab-ce 2>/dev/null
# Docker
docker exec <container> cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
# Helm / Kubernetes
helm list -A | grep -i gitlab
kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | grep -i gitlab
# Source installs
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
Then list every instance you run, not just the main one. Forgotten GitLab servers — a team’s self-hosted pilot, an acquired company’s instance, a disaster-recovery replica nobody upgrades — are exactly the ones still sitting on 18.x. Certificate-transparency logs and DNS history find them faster than an internal survey does.
GitLab published detection rules alongside the advisory (linked in the sources below). One looks for a native Ruby crash with Onigmo frames in puma_stderr.log; another for a burst of render time-outs on .org files from a single client in exceptions_json.log. GitLab is explicit that a crash only corroborates: a successful exploit “is quiet and does not reliably crash”, and the absence of a hit “never clears an attempt or a success”.
# A non-specific first look on a Linux-package install
sudo grep -E '\[BUG\]|Segmentation fault' /var/log/gitlab/puma/puma_stderr.log*
sudo grep '"exception.class":"Timeout::Error"' /var/log/gitlab/gitlab-rails/exceptions_json.log* \
| grep '"extra.class_name":"OtherMarkup"' | grep -c '\.org"'
If anything suggests code ran, GitLab’s guidance is to treat the instance as compromised: rotate the secrets in gitlab-secrets.json, CI/CD variables, runner registration tokens and access tokens. A GitLab server holds the keys to every pipeline it runs, so the blast radius is your deployment estate, not one application.
The CVE record lists no workaround; upgrading is the fix. Until then:
.org file.puma_stderr.log, exceptions_json.log and the Workhorse log are being collected, so the detection rules have something to read.CVE-2026-110264 is not in CISA’s Known Exploited Vulnerabilities catalogue, and no official source reports exploitation in the wild. CISA’s assessment, however, reads: exploitation “none”, automatable “yes”, technical impact “total”. That combination — no authentication, automatable, full control — is the profile that tends to be weaponised quickly.
About ten public GitHub repositories reference the CVE. By their own descriptions the most prominent is a crash-level, non-weaponised proof of concept; the rest are version checkers, detectors and lab setups. No confirmed public remote-code-execution exploit existed on 23 October.
Continuous attack-surface discovery works from certificate transparency, DNS history and live probing, so the pilot instance and the acquired company’s server turn up alongside the one in your inventory.
Because the version is not readable anonymously, we check it the way it can actually be checked — a credentialed audit, or the Sentinel agent reporting the installed `gitlab-ee` / `gitlab-ce` package. SemperWise One grades it against the fixed releases and raises a finding naming CVE-2026-110264.
In a penetration test we check what this CVE depends on: whether anonymous users can browse public projects, whether self-registration is open, and what a new account can reach. Those answers decide how urgent the upgrade is.
The finding closes when the installed version moves past the fix and is verified on retest — and reopens if a replica or restored backup brings the old version back.
/help only to signed-in users, and the version API needs a token. External testing can find every GitLab instance you expose; confirming the patch level needs an account, a token or server access — which is how a credentialed audit or an installed agent gets it.Regexp.new(params[:q]) — reach these bugs. Those should move to Ruby 4.0.9, 3.4.12 or 3.3.13. Ruby’s advisory notes that Regexp.timeout does not protect against them.Next step
A 30-minute call, then a scope document with what is in, what is out and what it costs. No obligation, and no charge for the conversation.