GitLab: an unauthenticated 10.0 RCE through Org-mode rendering
CVE-2026-110264 (CVSS 10.0): an integer overflow in GitLab's Onigmo regex engine, reached through the rendering of an Org-mode file, lets an anonymous user run code. It affects every version since 7.0, and the October 12 patch does not cover it. Fixed in 18.11.13 through 19.5.1.

GitLab's third regex flaw in a month, and the worst one
On October 21, 2026, GitLab shipped a critical patch for its self-managed Community and Enterprise editions. Leading it is CVE-2026-110264, rated 10.0, the maximum. Another flaw in the regular expression engine, after September's two memory corruptions and the integer overflow of October 12. But this one moves into a different category on two points that matter.
First, it is unauthenticated. No account, no project to create, no pipeline to submit. The earlier regex flaws needed at least a low-privilege account; this one fires through the plain rendering of content that GitLab displays. Second, it reaches all the way back to version 7.0, released in 2014. Twelve years of releases caught by a single line of advisory. If you host a GitLab, whatever its age, you should assume it is vulnerable until it runs a fixed version.
One last detail, and not a minor one: the October 12 patch does not protect against it. Instances updated nine days ago remain exposed.
The facts, as the advisory states them
| Item | CVE-2026-110264 |
|---|---|
| Class | Integer overflow (CWE-190), when compiling a regex |
| Component | The regular expression compiler (Ruby's Onigmo engine) |
| CVSS v3.1 | 10.0, AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H |
| Vector | Rendering of an Org-mode file served by GitLab |
| Authentication | None (PR:N) |
| Consequence | Code execution on the server, "under certain conditions" |
| Affected versions | From 7.0 up to before 18.11.13, then each 19.x branch before its fix |
| Fix | 18.11.13, 19.0.10, 19.1.9, 19.2.9, 19.3.6, 19.4.3, 19.5.1 (October 21, 2026) |
| Scope | Self-managed (GitLab.com and GitLab Dedicated already patched) |
| Status | No known exploitation, not in CISA's KEV catalog on October 21 |
A 10.0 leaves no room to argue about theoretical severity. The vector justifies it field by field: network attack (AV:N), low complexity (AC:L), no privileges (PR:N), no interaction from a legitimate user (UI:N), and above all S:C, the scope changes. The corruption does not stay inside the application, it reaches the server process and everything it can touch. That leaves the advisory's phrase, "under certain conditions." GitLab does not spell out which ones, and we come back to this below: it is the single grey area in an otherwise unambiguous advisory.
The mechanism
GitLab renders content you drop into your repositories, wikis, issues and snippets. Among the markup formats it supports is Org-mode, Emacs's note format, recognized by .org files. To display it as HTML, GitLab goes through the org-ruby library.
That is where it all plays out. According to the detection write-ups published around the patch, rather than the advisory itself, which stays quiet on this point, org-ruby builds a regular expression from certain keywords in the document, including the #+TODO: keyword, without sanitizing what it inserts. The content of your Org file therefore ends up directly inside the text of a regex, which GitLab then compiles with Onigmo, Ruby's regular expression engine.
Onigmo, compiling a crafted pattern, overflows. The write-ups describe an oversized repeat count that wraps an identifier stored in a signed 16-bit integer; the size calculation that follows is wrong, the engine reserves too little memory, and the write that comes next runs past the intended buffer. From there, the described upper bound is a controlled write turned into a system call, running under the git account that runs GitLab.
Keep a cool head about that last jump. The documented core is the overflow, so memory corruption and a crash of the worker rendering the page. Code execution is the outcome the advisory keeps in mind when it says RCE, but getting from one to the other depends on configuration, hardening and exploitation work, which is not trivial. No public exploit code was circulating for this CVE when the patch shipped.
From anonymous to code execution
What "unauthenticated" means here
The question that decides your real exposure: who, at your organization, can make GitLab render an Org-mode file without logging in? The advisory says "under certain conditions" and does not list the paths. So we reason from what GitLab renders to an anonymous visitor.
A public project is enough: its repository, wiki, issues and snippets are readable without an account, and GitLab renders .org files in them. On an instance that allows open registration or public project creation, an attacker creates the booby-trapped content themselves and then has it rendered. On a closed instance, they need a pre-existing public project, or another entry point that triggers Org rendering without a session. That uncertainty is exactly what the advisory's phrasing covers, and it is why you should not read "under certain conditions" as "probably not here."
Why the October 12 patch is not enough
Nine days earlier, on October 12, GitLab had already fixed a 10.0 integer overflow in the same regex engine, CVE-2026-97229, through versions 19.2.8, 19.3.5 and 19.4.2. Enough to believe the matter closed. It is not.
The two flaws share the root, Onigmo and its integer overflow, but not the entry point. CVE-2026-97229 went through the regex compiler in the CI/CD chain: a crafted regular expression in a pipeline configuration. CVE-2026-110264 goes through Org-mode rendering. The October 12 patch closed the CI/CD path without touching the Org path. The result: an instance moved to 19.4.2 on October 12 remains exposed to 110264, and must move again to 19.4.3.
A month of regex flaws in GitLab
The authenticated flaws
September 23, 2026
CVE-2026-89078 and CVE-2026-93577
a double free and an integer overflow, rated 9.9, in the evaluation of CI/CD regexes. A low-privilege account is required. Fixed in 19.2.7, 19.3.3 and 19.4.1.
The first unauthenticated path
October 12, 2026
CVE-2026-97229
a 10.0 integer overflow in the CI/CD regex compiler, this time unauthenticated. Fixed in 19.2.8, 19.3.5 and 19.4.2. Public exploit code circulates shortly after.
Org-mode rendering
October 21, 2026
CVE-2026-110264
a 10.0 integer overflow in Onigmo, reached through the rendering of an Org-mode file, unauthenticated, affecting every version since 7.0. The October 12 patch does not cover it. Fixed in 18.11.13, 19.0.10, 19.1.9, 19.2.9, 19.3.6, 19.4.3 and 19.5.1.
Affected versions
The advisory sets a single continuous range for the whole history before 19.0, then one bound per recent branch. The patch shipped on October 21, 2026.
| GitLab branch | Status | Fix |
|---|---|---|
| 7.0 through 18.11.12 | Vulnerable | 18.11.13 |
| 19.0.0 through 19.0.9 | Vulnerable | 19.0.10 |
| 19.1.0 through 19.1.8 | Vulnerable | 19.1.9 |
| 19.2.0 through 19.2.8 | Vulnerable | 19.2.9 |
| 19.3.0 through 19.3.5 | Vulnerable | 19.3.6 |
| 19.4.0 through 19.4.2 | Vulnerable | 19.4.3 |
| 19.5.0 | Vulnerable | 19.5.1 |
The line to watch is the first. Anything running below 18.11.13 is affected, regardless of branch: a 16.x, a 17.x, a forgotten 18.4. GitLab backported the fix only onto the latest 18.11; for an older version, remediation means a version upgrade, not a patch in place.
Checking your exposure
As with the earlier regex flaws, there is no safe remote test. Proving exposure would mean sending the crafted Org file to the instance, which means trying to overflow the engine and crash the worker rendering the page. That is exactly the denial of service you want to avoid on a production asset. Unlike a file read you confirm by reading a harmless public file, there is no benign marker here that proves the overflow without triggering it. The version remains the only reliable judge.
Three ways to read it, all from the inside:
- On the server,
sudo gitlab-rake gitlab:env:info(Omnibus install) gives the exact version. - Through the API,
curl --header "PRIVATE-TOKEN: <token>" https://gitlab.example.com/api/v4/version, which requires a token. - In the UI, the help page
/helponce logged in.
All three assume access. From the outside, a modern GitLab does not hand its version number to an anonymous visitor, by design. You can confirm that an instance is indeed a self-managed GitLab, which is most of the inventory work, but not read its patch level without authentication. That is a real limit for any inventory run from outside, and it is why the real subject is not testing but discovering the instances.
On the after-the-fact detection side, GitLab published two Sigma rules that apply to application logs: "Onigmo native worker crash" and "Org mode render error burst." They do not catch a successful silent exploit, but they flag the crashes and the bursts of render errors that give away attempts. Their absence proves nothing; their presence, a great deal.
Remediation
- Update to the fixed version for your branch: 18.11.13, 19.0.10, 19.1.9, 19.2.9, 19.3.6, 19.4.3 or 19.5.1. Even if you applied the October 12 patch: a 19.4.2 must move to 19.4.3. This is the only remediation that actually closes the Org-mode path.
- Inventory your self-managed GitLabs, including the ones nobody claims: a project's test instance, a subsidiary's GitLab, the one on a forgotten subdomain. It is often that one running a 2019 version, ticking both "unauthenticated" and "far behind."
- While the upgrade is pending, reduce the exposed surface: review which projects are public, turn off open registration if you do not need it, and if you do not use Org-mode, be aware there is no clean switch to disable it without touching the rest of the rendering. The update remains the answer.
GitLab, a recurring target
In a single month, GitLab has seen an unauthenticated file read at 10.0, two authenticated memory corruptions at 9.9, an unauthenticated integer overflow at 10.0 on October 12, and now this one. The vector changes every time, the conclusion holds: a self-managed instance concentrates an organization's code, secrets and deployment keys, which makes it a prime target, and its regex engine has proven a seam of flaws.
An annual pentest catches none of these: an October 21 disclosure is absent from a report dated last spring. What catches them is an up-to-date inventory of exposed assets and monitoring that spots the instance left one patch behind, without waiting for the next audit. Provided you know your whole perimeter, undeclared GitLabs included.
Where Flawfence fits in
This flaw is unauthenticated, but confirming it remotely would go through exploitation, so through a risk of crashing a production asset that we refuse to run. Our scanner therefore does not claim to prove exploitability from the outside. Its value is on what is most often missing: finding the GitLab instance you had forgotten, and flagging it as sensitive.
Faced with an advisory like this one, Flawfence discovers your exposed GitLabs across all your domains and subdomains, Shadow IT included, reports the version when it is readable, flags every self-managed instance as an asset to keep updated, and monitors continuously so that a newly exposed GitLab or a version left behind raises an alert the same day. We also publish the version-based Nuclei detection template for this CVE, a deliberately non-destructive detection that situates the instance without ever sending the payload.
Frequently asked questions
Do you need an account to exploit this flaw?
No. The vector carries PR:N: no authentication is required. That is what sets it apart from the two memory corruptions of September 23, which needed a low-privilege account. The advisory notes "under certain conditions" without detailing them; in practice, the most obvious condition is that some Org-mode content is rendered to an anonymous visitor, for example through a public project.
If I applied the October 12 patch, am I protected?
No. The October 12 patch (CVE-2026-97229) closed the CI/CD path of the same engine, not the Org-mode path. An instance on 19.2.8, 19.3.5 or 19.4.2 remains exposed to CVE-2026-110264 and must move to 19.2.9, 19.3.6 or 19.4.3.
How far back in time are versions affected?
Every version since 7.0, released in 2014, is affected. There is no spared older branch. For anything before 18.11, the single fix is 18.11.13; a 16.x or a 17.x must therefore upgrade, not just apply a patch in place.
Is it being actively exploited?
When the patch shipped, no exploitation in the wild was reported, no public exploit code was circulating for this CVE, and it was not in CISA's catalog of actively exploited vulnerabilities. Getting from the documented overflow to reliable code execution takes work that is not immediate. That is no reason to wait: the patch describes the defect and maps the path, and a proof of concept already exists for the sibling flaw of October 12.
How do I check my version without risking a crash?
Through the version, never through an active test. On the server, sudo gitlab-rake gitlab:env:info gives the exact version; in the UI, /help shows it once logged in; through the API, GET /api/v4/version returns it with a token. Sending a crafted Org file to "see if it goes through" amounts to attempting exploitation, with denial of service at the end. You do not do that on a production asset.
What to take away
Content rendered by the server is an input like any other. The moment a document keyword ends up, unsanitized, inside the text of a regular expression, the engine compiling it must bound its edge cases, or it ends up writing where it should not. For you, the difficulty is not testing, which cannot be done remotely without risk, but knowing where your GitLab instances are and which version they run. With an unauthenticated flaw reaching back to 2014, every forgotten GitLab is an open door. It is inventory work, not exploit work.
Let’s discuss your external exposure
Request a personalized Flawfence demo and discover your real exposure level.
