GitLab CVE-2026-97229: The CVSS 10.0 RCE Vulnerability Exposing 26,000+ CI/CD Pipelines to Attack

The CyberSec Guru

Updated on:

GitLab CVE-2026-97229

If you like this post, then please share it:

Buy me A Coffee!

Support The CyberSec Guru’s Mission

🔐 Fuel the cybersecurity crusade by buying me a coffee! Why your support matters: Zero paywalls: Keep the main content 100% free for learners worldwide.

“Your coffee keeps the servers running and the knowledge flowing in our fight against cybercrime.”☕ Support My Work

Buy Me a Coffee Button

A complete technical analysis of the Onigmo regex integer overflow, the unauthenticated exploit chain, and actionable threat hunting strategies to secure your software supply chain.

On October 12, 2026, GitLab released emergency out-of-band patches for CVE-2026-97229, a maximum-severity remote code execution (RCE) vulnerability that carries a perfect CVSS score of 10.0. Within 24 hours of the disclosure, researchers at Rapid7 had independently reproduced arbitrary code execution against an unpatched official GitLab Community Edition (CE) image. By October 16, security researcher Jonah Burgess published a fully weaponized proof-of-concept (PoC) exploit on GitHub.

According to telemetry from Censys, nearly 26,000 exposed GitLab hosts were identified as vulnerable at the time of disclosure, which makes this a live, exploitable threat against core software development infrastructure rather than a problem confined to bug bounty reports. The vulnerability affects self-managed GitLab CE and Enterprise Edition (EE) instances running versions from 19.2 before 19.2.8, 19.3 before 19.3.5, and 19.4 before 19.4.2.

The flaw sits inside the CI/CD regular expression compiler, the component that parses pipeline configurations and handles build and deployment secrets. An attacker who successfully exploits this flaw can execute arbitrary operating system commands on the GitLab server as the git account. Compromising the git user hands an attacker proprietary source code, CI/CD environment variables, cloud provider credentials, and everything downstream in the software supply chain.

Breaking down the CVSS 10.0 score

In the cybersecurity industry, a CVSS 10.0 rating is exceptionally rare and represents the worst-case scenario for any software vulnerability. The CVSS 3.1 vector string for CVE-2026-97229 is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H. Here’s what each part means and why it demands drop-everything remediation.

  • AV:N (Attack Vector: Network): The vulnerability is exploitable remotely over the network, requiring no local access or physical proximity to the target server.
  • AC:L (Attack Complexity: Low): Exploitation does not rely on race conditions, specific network topologies, or improbable environmental circumstances. The attack is deterministic and reliable.
  • PR:N (Privileges Required: None): This is the most alarming metric for enterprise defenders. The final detonation of the payload requires no authentication: no API tokens, no session cookies, no authorization headers.
  • UI:N (User Interaction: None): The exploit does not require an administrator to click a malicious link or render a crafted HTML page. It executes silently via automated API requests.
  • S:C (Scope: Changed): This indicates that the vulnerability allows the attacker to break out of the vulnerable component’s security boundary. While the flaw exists in the regex compiler, the impact extends to the underlying operating system and adjacent microservices.
  • C:H/I:H/A:H (Impact: High across Confidentiality, Integrity, and Availability): A successful exploit results in total system compromise. Attackers can exfiltrate source code (Confidentiality), inject malicious backdoors into the main branch (Integrity), or wipe the server and crash the pipeline infrastructure (Availability).

A perfect score across every metric is why advanced persistent threats (APTs) and ransomware operators treat vulnerabilities like this one as priority targets for supply chain attacks.

Why the git user matters so much

The blast radius of this vulnerability depends on how a self-managed GitLab instance is actually built. GitLab runs as a set of interconnected microservices, background workers, and reverse proxies rather than a single monolithic web app.

When a user interacts with the GitLab web interface, their requests are first intercepted by GitLab Workhorse, a reverse proxy designed to take pressure off the application server by handling slow and large HTTP requests, such as massive Git pushes or file downloads. Behind Workhorse sits Puma, the application server that serves the actual Ruby on Rails monolith.

The heavy lifting of GitLab’s CI/CD pipeline, though, is handled by Sidekiq, a job queue that uses Redis as a non-persistent database backend for job metadata, scheduling, and incoming tasks. All Git repository operations are abstracted through Gitaly, a service that provides high-level Remote Procedure Call (RPC) access to the underlying Git repositories.

When CVE-2026-97229 is exploited, the arbitrary code executes within the context of the Puma or Sidekiq worker processes, which run under the git system user. In a standard Omnibus GitLab installation, the git user has deep read/write access to the Gitaly storage volumes, the Sidekiq job queues, and the Redis cache.

📬 Stay Ahead of Cyber Threats

Get the latest cybersecurity news, critical vulnerabilities, threat intelligence, tutorials, and exclusive giveaways delivered straight to your inbox. No spam. Unsubscribe anytime.

Subscribe to the Newsletter →

An attacker operating as the git user doesn’t need to escalate privileges to root to achieve their primary objectives. They can silently modify .gitlab-ci.yml files in critical repositories, inject malicious scripts into the build process, harvest AWS/Azure/GCP credentials stored in CI/CD variables, and intercept the deployment pipeline to push compromised artifacts to production. Compromising the git user effectively compromises the whole supply chain downstream of it.

Onigmo, bytecode, and the integer overflow (CWE-190)

Most developers and security researchers associate regular expression vulnerabilities with ReDoS (Regular Expression Denial of Service), where poorly constructed patterns cause catastrophic backtracking that exhausts CPU cycles and freezes the application. CVE-2026-97229 works differently, and it’s more dangerous: it’s a memory corruption vulnerability rooted in the regex compiler, not the matcher.

GitLab relies on Ruby’s native regex engine, Onigmo (a fork of the Oniguruma library) [[4]]. Onigmo is a C-based engine that compiles human-readable regular expressions into an intermediate bytecode before execution [[26]]. This compilation process involves parsing the regex string, generating an Abstract Syntax Tree (AST), and calculating the memory required to store the resulting bytecode instructions.

The root cause of CVE-2026-97229 is classified as CWE-190: Integer Overflow or Wraparound. During the compilation phase, Onigmo calculates the program-size to allocate a heap buffer for the bytecode. The exploit takes advantage of a gap between GitLab’s application-level validation logic and Onigmo’s low-level compilation behavior.

The two-stage validation bypass and TOCTOU

GitLab implements strict size limits on CI/CD regex patterns to prevent resource exhaustion. The exploit bypasses this using a Time-of-Check to Time-of-Use (TOCTOU) vulnerability tied to character encoding contexts.

  1. The Time-of-Check (US-ASCII context): The attacker crafts a malicious regex containing an inline comment nested deeply inside a quantifier. When GitLab’s initial validation scanner evaluates the string in US-ASCII mode, the inline comment is parsed safely, and the overall string length remains under the size limits enforced by the CI/CD linter. The validation check passes.
  2. The Time-of-Use (UTF-8 context): The vulnerability manifests in the handling of include.rules.exists.regexp, a mechanism that matches repository file paths to determine if a CI/CD job should be instantiated. The attacker ensures the repository path contains multi-byte UTF-8 characters. When the CI linter evaluates the regex against this UTF-8 path, Onigmo detects the encoding mismatch and is forced to switch contexts, recompiling the pattern for UTF-8.

During this UTF-8 recompilation, the internal calculation for the bytecode buffer size overflows a 32-bit integer boundary. Instead of allocating a massive buffer (which would trigger an out-of-memory exception and halt the process), the integer wraps around to a small, seemingly valid number. Onigmo then writes the much larger bytecode into this undersized heap buffer.

From bytecode corruption to shell access

This results in a classic heap-based buffer overflow. By carefully crafting the AST of the regex, the attacker corrupts adjacent memory structures on the heap, specifically targeting function pointers, object headers, or Ruby C-extension metadata. This redirects the execution flow of the regex engine: instead of executing a benign string match, the corrupted bytecode forces the engine to jump to an attacker-controlled memory address or invoke a native C function like system() or exec(). The PoC demonstrates this by executing standard reconnaissance commands like uname -a && id, confirming arbitrary code execution as the git user.

The exploit chain, step by step

Exploit chain of CVE-2026-97229 takes three stages.

GitLab CVE-2026-97229 Exploit Chain
GitLab CVE-2026-97229 Exploit Chain

Planting the payload

The attack begins with a seemingly innocuous action: pushing a branch to a public project. The attacker needs a standard GitLab account with permission to push to a public repository, a low bar on most self-managed deployments that allow open user registration or have public project creation enabled by default.

The attacker commits a malicious .gitlab-ci.yml configuration file containing the specially crafted regular expression with the inline comment and quantifier trick. They also make sure the repository contains file paths with UTF-8 characters, which triggers the encoding switch during the linter phase.

Triggering the overflow

The entry point is GitLab’s public CI lint endpoint. The attacker sends a carefully constructed HTTP GET request:

GET /api/v4/projects/:id/ci/lint?content_ref=ATTACKER_BRANCH HTTP/1.1
Host: target-gitlab.instance.com

There’s no authentication here at all: no PRIVATE-TOKEN, no Authorization: Bearer header, no session cookie. The server receives the request, pulls the malicious .gitlab-ci.yml from the specified branch, and initiates the CI linting process. It attempts to compile the regex and match it against the UTF-8 repository paths. This “compile + match” operation is the exact moment the integer overflow is triggered.

Detonation and the 502 smoke screen

As the regex engine attempts to write the oversized bytecode into the undersized heap buffer, memory corruption occurs and the attacker’s shellcode executes. The payload typically initiates a reverse shell or makes an outbound DNS/HTTP callback to a Command and Control (C2) server to confirm successful exploitation.

Immediately after the payload executes, the corrupted heap state causes the Ruby worker process (Puma or Sidekiq) to crash. The web server, unable to get a response from the crashed worker, returns an HTTP 502 Bad Gateway error to the attacker.

This 502 error helps the attacker and hurts defenders. A security operations center (SOC) might read a spike in 502 errors as a minor application stability issue or a poorly written regex causing a denial of service. But by the time that error shows up, the payload has already run, the C2 beacon is established, and the attacker may already be moving laterally through the network.

Resource constraints and target viability

This exploit isn’t lightweight. The generated bytecode required to reliably corrupt the heap and achieve instruction pointer (RIP) control is slightly larger than 2 GiB, and a single-node test instance needs roughly 9 GiB of available RAM to process the request without triggering the Linux Out-Of-Memory (OOM) killer before detonation. That resource requirement acts as a natural barrier against low-tier botnets going after edge devices, but it poses essentially no obstacle for well-resourced ransomware gangs or state-sponsored APTs targeting enterprise infrastructure, where GitLab servers routinely run with 32GB to 128GB of RAM.

The CI/CD attack surface in 2026

CVE-2026-97229 is the latest in a run of critical vulnerabilities hitting GitLab’s CI/CD configuration processing pipeline, and the pattern points to a shift in where attackers are putting their effort.

In September 2026, GitLab patched CVE-2026-85706, a CVSS 10.0 file read flaw that saw in-the-wild probes within hours of public disclosure. Weeks later, on September 23, GitLab released patches for CVE-2026-93577 and CVE-2026-89078, two additional RCE flaws in the exact same CI/CD regex subsystem. Version 19.4.1, which was supposed to fix those September flaws, was then broken again by Rapid7 researchers, showing the attack surface was wider than anyone had mapped.

This pattern suggests that GitLab’s CI/CD pipeline is currently a high-value, high-yield attack surface. Roman Y. Sannikov, global research coordinator at iCounter, noted that “a CVSS 10.0 in GitLab gets attackers’ attention fast because of what sits behind it: a self-managed GitLab server holds an organization’s source code, its build pipelines, and usually the credentials those pipelines use to reach cloud accounts, package registries and production.”

Threat actors have realized that compromising a CI/CD pipeline is far more efficient than trying to breach a hardened perimeter firewall. By poisoning the build pipeline, attackers can ensure that every subsequent deployment to production automatically includes their backdoors, rootkits, or cryptominers, giving them persistent, self-replicating access across the enterprise.

Other vulnerabilities patched in the October 12 release

While CVE-2026-97229 dominates the headlines, the October 12 emergency patch release addressed several other high-severity vulnerabilities that enterprise defenders need to remediate:

  • CVE-2026-92883 (CVSS 8.7): A Cross-Site Scripting (XSS) vulnerability that could allow an authenticated user to execute arbitrary JavaScript in other users’ browser sessions via a specially crafted repository. This could lead to session hijacking and unauthorized pipeline modifications.
  • CVE-2026-16301 (CVSS 8.5): An improper authorization flaw in the downstream pipeline creation service. This allows an authenticated user with a standard Developer role to execute CI/CD pipelines on protected branches, bypassing branch protection rules and potentially deploying unreviewed code to production.
  • CVE-2026-14814 (CVSS 8.2): A permissive regular expression vulnerability that could allow a user to poison cached responses for raw repository files. This cache poisoning could cause targeted users’ CI/CD pipelines to execute specially crafted content, potentially exposing protected environment variables and cloud credentials.

This clustering is a strong argument for aggressive patch management and closer code review of pipeline configurations.

Mitigation, patching, and threat hunting

The window for action is closing fast. With a working PoC publicly available, automated scanning and exploitation attempts are already underway, and organizations need to move past passive vulnerability management toward active defense.

Check your version and patch now

Administrators must immediately verify their GitLab version and apply the out-of-band patches. Single-node instances will see brief downtime during the upgrade due to mandatory database migrations.

Verify your version:

sudo gitlab-rake gitlab:env:info | grep "GitLab version"

Upgrade Instructions (Debian/Ubuntu):

sudo apt-get update
sudo apt-get install gitlab-ee=19.4.2-ee.0 # Or the corresponding CE/19.3/19.2 version
sudo gitlab-ctl restart

Upgrade Instructions (RHEL/CentOS):

sudo yum install gitlab-ee-19.4.2-ee.0.el8.x86_64
sudo gitlab-ctl restart

Interim mitigations if you can’t patch yet

If your management prevents immediate patching, you need to reduce the attack surface. There is no configuration to disable the vulnerable code path.

  • Disable Public Registration: Immediately disable new user registration and restrict public project creation to administrators only.
  • WAF Rules: Place the GitLab instance behind a Web Application Firewall (WAF) configured to block unauthenticated requests to /api/v4/projects/*/ci/lint that originate from outside the corporate IP range.
  • Network Segmentation: Ensure the GitLab server cannot initiate outbound connections to the internet, severing the C2 callback mechanism required for reverse shells.

Threat hunting in your SIEM

Security teams need to actively hunt for indicators of compromise (IoCs) in their SIEM platforms. The primary network indicator is an unauthenticated request to the CI lint endpoint followed immediately by a 502 error.

Splunk Query:

index=gitlab_logs uri_path="/api/v4/projects/*/ci/lint" http_status=502 user_agent!="GitLab-Runner/*"
| stats count by src_ip, uri_path, _time
| where count > 5

Elasticsearch / Kibana (KQL) Query:

http.request.method : "GET" AND
url.path : "/api/v4/projects/*/ci/lint" AND
http.response.status_code : 502 AND
NOT user.name : "gitlab-runner"

Host-based hunting with auditd and Sysmon

Because the exploit results in arbitrary code execution as the git user, host-based monitoring is critical. Defenders should look for unexpected child processes spawned from Puma or Sidekiq workers, or outbound network connections initiated by the git user.

Linux Auditd Rule to Detect Suspicious Git User Execution:

-a always,exit -F arch=b64 -S execve -F uid=git -F exe!=/opt/gitlab/embedded/bin/* -F exe!=/usr/bin/git -k gitlab_suspicious_exec

This rule triggers an alert whenever the git user executes a binary that isn’t part of the standard GitLab Omnibus embedded binaries or the standard Git executable, catching reverse shells, curl/wget downloads, or Python/Perl scripts spawned by the exploit.

Security hygiene after patching

Even after patching, organizations should operate under the assumption that a breach may have occurred before the patch was deployed.

  • Rotate All CI/CD Secrets: Immediately rotate all AWS access keys, Azure service principals, GitHub Personal Access Tokens (PATs), and Docker registry passwords stored in GitLab CI/CD variables.
  • Audit .gitlab-ci.yml History: Review the commit history of all critical repositories for unauthorized modifications to pipeline configurations, particularly the introduction of new include rules or obfuscated script blocks.
  • Review Runner Activity: Analyze the logs of your GitLab Runners for unexpected job executions, unusual network egress, or the downloading of unknown binaries during the build phase.

Where supply chain security goes from here

CVE-2026-97229 shows that CI/CD infrastructure isn’t just a developer convenience anymore. It’s a Tier-1 security boundary, and when that boundary is breached, the attacker gains implicit trust and access to everything the pipeline touches.

Defending against the next version of this attack means enterprises need a zero-trust architecture for their software supply chain. That means moving away from persistent, long-lived runners toward ephemeral, containerized build environments that are destroyed immediately after job completion. It also means implementing pipeline-as-code signing using frameworks like Sigstore and adhering to the SLSA (Supply-chain Levels for Software Artifacts) framework, so no code can be injected into the build process without cryptographic verification.

With a working PoC for CVE-2026-97229 now public and nearly 26,000 exposed hosts identified by Censys, the question isn’t whether attackers will try to exploit this vulnerability. It’s whether your organization patches before they succeed. The patch is out, the exploit is public, and every hour a self-managed GitLab instance stays unpatched is an hour of unnecessary risk. Audit your logs, rotate your secrets, and patch your servers.

Buy me A Coffee!

Support The CyberSec Guru’s Mission

🔐 Fuel the cybersecurity crusade by buying me a coffee! Your contribution powers free tutorials, hands-on labs, and security resources.

Why your support matters:
  • Writeup Access: Get complete writeup access within 12 hours
  • Zero paywalls: Keep the main content 100% free for learners worldwide

Perks for one-time supporters:
☕️ $5: Shoutout in Buy Me a Coffee
🛡️ $8: Fast-track Access to Live Webinars
💻 $10: Vote on future tutorial topics + exclusive AMA access

“Your coffee keeps the servers running and the knowledge flowing in our fight against cybercrime.”☕ Support My Work

Buy Me a Coffee Button

If you like this post, then please share it:

Exploits

Discover more from The CyberSec Guru

Subscribe to get the latest posts sent to your email!

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from The CyberSec Guru

Subscribe now to keep reading and get access to the full archive.

Continue reading