Someone can slip a booby-trapped regex into a merge request and own your entire source code vault
CVE-2026-93577 is an integer overflow (CWE-190) in the regular expression compiler that GitLab CE/EE uses to parse CI/CD pipeline configurations. An authenticated user — anyone who can push a .gitlab-ci.yml file or open a merge request against a repo with CI enabled — can craft a regex pattern that triggers the overflow during compilation. The overflow corrupts memory in a way that yields arbitrary code execution on the GitLab application server process. Affected versions span every release from 19.2 through 19.2.6, 19.3 through 19.3.2, and 19.4.0. It shares the same regex-engine attack surface with companion bug CVE-2026-89078 (a double-free in the same parser). Fixed in 19.2.7, 19.3.3, and 19.4.1, released 2026-09-23.
The vendor CVSS of 9.9 is *justified and, if anything, generous only in the decimal*. The vector — AV:N/AC:L/PR:L/UI:N/S:C — accurately captures the low bar: network-reachable, trivial complexity, low-privilege auth, no user interaction, scope-change to the underlying server. GitLab is not a commodity workstation app; it is the CI/CD platform, the artifact store, the container registry, and the source-code repository for most organizations that deploy it. RCE on this host is tantamount to supply-chain compromise. The only friction is the authentication gate, and GitLab instances routinely allow self-registration, external contributors, or broad internal user bases — making that gate thinner than the CVSS PR:L label implies. No public PoC or wild exploitation is confirmed yet, which shaves a hair off urgency but does not change the blast radius.
5 steps from start to impact.
Obtain authenticated GitLab session
/users/sign_up), guest access to public projects, or external contributor accounts. Alternatively, a compromised developer credential (phished, leaked, reused) suffices. The required privilege level is the lowest GitLab role — Guest or Reporter with fork access is enough to create a CI config in a forked repo.- Target runs GitLab CE/EE 19.2–19.4 in a vulnerable version range
- Attacker can register or already holds any authenticated account
- Instances with registration disabled and strict IdP-gated SSO narrow the attacker pool significantly
- Guest accounts on private-only instances cannot fork repos without explicit group membership
AuditEvents API), new-account-creation alerts, IdP sign-in anomaly detection.Craft malicious .gitlab-ci.yml with overflow regex
.gitlab-ci.yml file containing a specially constructed regular expression that triggers an integer overflow in the regex compiler during pipeline parsing. The regex pattern is designed to make an internal size computation wrap around, leading to an undersized buffer allocation. No special tooling beyond a text editor is needed — the pattern is a static string. The companion CVE-2026-89078 targets the same parser with a double-free variant, giving the attacker two independent memory corruption primitives.- Knowledge of the overflow trigger pattern (not yet public but trivially reverse-engineerable from the patch diff)
- No public PoC exists yet, so attackers must invest effort in diffing the patch — but this is routine for skilled adversaries and typically takes hours to days after patch release
.gitlab-ci.yml diffs for anomalous regex complexity; no vendor-supplied detection signature exists yet.Push config to trigger pipeline parsing
.gitlab-ci.yml to any branch (including in a fork they control). GitLab's pipeline creation subsystem automatically parses the file, invokes the regex compiler, and hits the overflow. In many configurations, even a draft merge request triggers pipeline evaluation. The attacker does not need to wait for a maintainer to approve or merge anything — the parse happens at push time.- Repo has CI/CD enabled (default for most GitLab projects)
- Pipeline runs are not gated behind manual approval for the attacker's branch/fork
- Organizations using
only: protectedor CI/CD job approval policies may block automatic pipeline creation from forks - GitLab Premium/Ultimate
security policiescan restrict who triggers pipelines
Achieve arbitrary code execution on GitLab server
git user (or whatever user the GitLab application process runs as — often git or gitlab). This user typically has read access to all repositories, CI/CD secrets, and runner registration tokens.- Heap layout must be somewhat predictable — typical for long-running Ruby/Go processes with stable allocation patterns
- ASLR and heap hardening on modern Linux may require multiple attempts, but the attacker can retry by pushing additional commits
- SELinux/AppArmor in enforcing mode may limit post-exploitation actions (but most GitLab Omnibus installs do not confine the application process)
/var/log/gitlab/; kernel audit for execve from git user.Pivot to supply-chain compromise
RAILS_CONSOLE or direct database access), inject backdoors into source code, poison container registry images, mint new personal access tokens for persistence, and register rogue CI runners. This is a full supply-chain takeover — every artifact built by this GitLab instance is now suspect.- GitLab server process has access to the PostgreSQL database and Git repository storage (always true in standard Omnibus/Docker installs)
- Network segmentation between GitLab and production deployment targets may slow lateral movement
- Code review practices may catch injected backdoors in high-value repos, but the attacker can target less-reviewed repos or inject into build scripts rather than source
The supporting signals.
| In-the-wild exploitation | Not confirmed. No active exploitation reported as of 2026-09-24. Not listed in CISA KEV. Disclosed <24 hours ago — window for weaponization is open. |
|---|---|
| Proof-of-concept | No public PoC. Reported by *joaxcar* via HackerOne #3995696. Patch diff is available and the regex compiler is a constrained target — expect weaponized PoC within days to low weeks. |
| EPSS score | Not yet scored — CVE is <24 hours old. Given the RCE impact, network vector, and GitLab's install base, expect EPSS to settle in the top 5% once scored. |
| KEV status | Not listed as of 2026-09-24. Monitor CISA KEV catalog — GitLab CVEs with RCE impact have historically been added within weeks of PoC release. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H — 9.9. Network-accessible, low complexity, low privilege (any authenticated user), no user interaction, scope change (breaks out of regex context to server). The S:C is the key driver: the vuln is in the CI parser but impact is on the underlying OS. |
| Affected versions | GitLab CE/EE 19.2.0–19.2.6, 19.3.0–19.3.2, 19.4.0. Versions prior to 19.2 are *not* affected — the vulnerable regex compiler was introduced in 19.2. |
| Fixed versions | 19.2.7, 19.3.3, 19.4.1 — released 2026-09-23. GitLab.com (SaaS) is already patched. GitLab Dedicated customers patched automatically. |
| Internet exposure | Shodan/Censys show >20,000 self-managed GitLab instances on public internet (per CyCognito footprint data from September 2026). ZoomEye indexes ~1.26M IPv4 matches for the GitLab fingerprint globally. |
| Companion vulnerability | CVE-2026-89078 — double-free in the same regex parser/compiler, also CVSS 9.9, fixed in the same patch release. Treat as a pair; patching one patches both. |
| Researcher / disclosure | Reported by joaxcar via GitLab's HackerOne bug bounty program. Coordinated disclosure with patch release on 2026-09-23. Hype score 11/100 per CVEMon — low public attention so far, but expected to spike. |
Why this verdict
- Vendor baseline is fair. The CVSS 9.9 accurately models the network-accessible, low-complexity, auth-to-RCE chain with scope change. The
PR:Lis correctly assessed — any authenticated GitLab user with push access to any repo (including forks) can trigger the vulnerable code path. No adjustment needed for vector accuracy. - Authentication friction is real but thin. The
PR:Lrequirement means the attacker needs an account. However, GitLab self-managed instances commonly allow open self-registration, external contributor access, or have broad internal user populations (hundreds to thousands of developers). This is not the same friction as, say, requiring domain admin. Downward adjustment: −0.2 for the auth gate. - No PoC or exploitation yet — but the clock is ticking. The patch shipped <24 hours ago and no public exploit exists. This reduces *immediate* urgency slightly but does not change the structural severity. The patch diff is public and the regex compiler is a well-understood attack surface — weaponization timeline is days, not months. Downward adjustment: −0.1 for current threat maturity.
- Role multiplier: GitLab is a canonical CI/CD and supply-chain component. Per the high-value role catalog, GitLab occupies the *CI/CD + artifact stores* and *supply-chain registries* categories. Essentially 100% of GitLab installations serve this role by definition — it is not a component that *sometimes* runs in a high-value position; it *always* does. RCE on the GitLab server yields: (a) read/write access to all source code repositories, (b) exfiltration of all CI/CD secrets, deployment tokens, and API keys, (c) ability to inject backdoors into build pipelines and source code (supply-chain attack), (d) poisoning of container registry images, (e) minting of persistent access tokens, (f) pivot to runner infrastructure. The blast radius is supply-chain-scale. This floors the verdict at CRITICAL regardless of authentication friction.
- Internet exposure compounds the risk. Over 20,000 self-managed GitLab instances are directly internet-facing per Shodan/Censys, and many accept user registrations. The attack does not require internal network access — it is fully remote.
Why not higher?
The CVSS ceiling is 10.0, which would require PR:N (unauthenticated). This vulnerability requires authentication — even if the bar is low, it is nonzero. A CVSS 10.0 or a score above 9.6 would overstate the ease of initial access. The current 9.6 correctly reflects the virtually-guaranteed supply-chain impact gated behind a single, often-thin authentication check.
Why not lower?
Any attempt to downgrade below CRITICAL fails the deployment-role floor test. GitLab is definitionally a CI/CD platform — 100% of installs occupy the high-value role. RCE on this component is supply-chain compromise by definition. The authentication requirement is the only friction point, and it is insufficient to breach the CRITICAL floor: GitLab's self-registration defaults, broad internal user bases, and external contributor models mean the attacker population is large. Downgrading to HIGH would require evidence that <1% of GitLab instances are reachable or that the auth gate is genuinely restrictive — neither is true.
What to do — in priority order.
- CRITICAL 9.6→CRITICAL 9.2Disable open user registration immediately — Navigate to Admin Area → Settings → General → Sign-up restrictions and uncheck *Sign-up enabled*. This eliminates the easiest path for external attackers to obtain the required authenticated session. Enforce SSO/SAML as the sole authentication method if possible. Deploy within the noisgate mitigation SLA of 3 days for CRITICAL findings — ideally within hours given the low effort required.
- CRITICAL 9.6→HIGH 8.2Restrict CI/CD pipeline creation from forks and unprotected branches — Set Settings → CI/CD → General pipelines → CI/CD configuration fetch strategy to limit pipeline triggers to protected branches only. Enable merge request approval policies that require maintainer approval before CI runs on MR pipelines from forks. This breaks step 3 of the attack path for external contributors and low-privilege users. Deploy within 3 days.
- CRITICAL 9.6→CRITICAL 9.0Deploy host-based monitoring on the GitLab server — Install or verify EDR/agent coverage on the GitLab application server. Alert on: (a) unexpected child processes spawned by Puma or Sidekiq workers, (b)
execvecalls from thegituser that are not standard Git operations, (c) crash dumps or segfaults in/var/log/gitlab/. This does not prevent exploitation but enables rapid detection and response. Deploy within 3 days. - CRITICAL 9.6→CRITICAL 9.0Place GitLab behind a WAF or reverse proxy with authentication hardening — If GitLab is internet-facing, ensure it sits behind a WAF (Cloudflare, AWS WAF, Imperva) or reverse proxy that can rate-limit and log API/Git push requests. Enforce MFA for all users via the IdP. While a WAF cannot inspect
.gitlab-ci.ymlcontent for malicious regexes, MFA and rate-limiting raise the cost of credential abuse. Deploy within 3 days. - CRITICAL 9.6→IGNORE 0.0Apply the vendor patch (19.2.7, 19.3.3, or 19.4.1) — This is the definitive fix. Upgrade your GitLab self-managed instance to the patched version corresponding to your release train. Single-node instances will experience brief downtime for database migrations; multi-node deployments can use zero-downtime upgrade procedures. This is the only control that fully eliminates the vulnerability. Per the noisgate remediation SLA for CRITICAL, complete within 90 days — but given the supply-chain blast radius and imminent PoC likelihood, aim for <7 days.
- Network-level IP allowlisting for Git pushes — does not help if the attacker is an authorized internal user or has legitimate VPN access; the attack originates from a valid authenticated session, not a network anomaly.
- GitLab CI/CD
includerestrictions — restrictinginclude:directives does not mitigate this because the malicious regex is in the top-level.gitlab-ci.ymlrules:oronly:blocks, not in an included file. - Container-level sandboxing of CI runners — irrelevant because the vulnerability is in the *GitLab server's pipeline parser*, not in the runner execution environment. The RCE happens before any runner is invoked.
- Disabling GitLab Pages or Container Registry — does not address the vulnerable regex compiler in the CI/CD configuration parser; these are unrelated subsystems.
Crowdsourced verification payload.
Run this script on the GitLab server itself (or any host that can reach the GitLab API) as any user with curl access. Invoke with: bash check_cve_2026_93577.sh https://gitlab.example.com <PRIVATE_TOKEN>. The private token needs only read_api scope (any user). No root/sudo required.
#!/usr/bin/env bash
# check_cve_2026_93577.sh — Verify GitLab is patched against CVE-2026-93577
# Usage: bash check_cve_2026_93577.sh <GITLAB_URL> <API_TOKEN>
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
GITLAB_URL="${1:-}"
TOKEN="${2:-}"
if [[ -z "$GITLAB_URL" || -z "$TOKEN" ]]; then
echo "Usage: $0 <GITLAB_URL> <API_TOKEN>"
echo "UNKNOWN — missing arguments"
exit 2
fi
# Strip trailing slash
GITLAB_URL="${GITLAB_URL%/}"
# Query GitLab version API
RESPONSE=$(curl -sf --max-time 10 \
-H "PRIVATE-TOKEN: $TOKEN" \
"${GITLAB_URL}/api/v4/version" 2>/dev/null) || {
echo "UNKNOWN — could not reach GitLab API at ${GITLAB_URL}"
exit 2
}
VERSION=$(echo "$RESPONSE" | grep -oP '"version"\s*:\s*"\K[^"]+' 2>/dev/null) || {
echo "UNKNOWN — could not parse version from API response"
exit 2
}
echo "Detected GitLab version: $VERSION"
# Parse major.minor.patch
IFS='.' read -r MAJOR MINOR PATCH <<< "$(echo "$VERSION" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+')"
if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
echo "UNKNOWN — could not parse version components from '$VERSION'"
exit 2
fi
# Vulnerable ranges:
# 19.2.0 - 19.2.6 (fixed in 19.2.7)
# 19.3.0 - 19.3.2 (fixed in 19.3.3)
# 19.4.0 (fixed in 19.4.1)
# Versions < 19.2 are NOT affected.
if (( MAJOR < 19 )); then
echo "PATCHED — version $VERSION predates the vulnerable code (introduced in 19.2)"
exit 0
fi
if (( MAJOR > 19 )); then
echo "PATCHED — version $VERSION is beyond the affected major release"
exit 0
fi
# MAJOR == 19
if (( MINOR < 2 )); then
echo "PATCHED — version $VERSION predates the vulnerable code (introduced in 19.2)"
exit 0
fi
if (( MINOR == 2 )); then
if (( PATCH >= 7 )); then
echo "PATCHED — version $VERSION contains the fix (19.2.7+)"
exit 0
else
echo "VULNERABLE — version $VERSION is in the affected range (19.2.0–19.2.6)"
exit 1
fi
fi
if (( MINOR == 3 )); then
if (( PATCH >= 3 )); then
echo "PATCHED — version $VERSION contains the fix (19.3.3+)"
exit 0
else
echo "VULNERABLE — version $VERSION is in the affected range (19.3.0–19.3.2)"
exit 1
fi
fi
if (( MINOR == 4 )); then
if (( PATCH >= 1 )); then
echo "PATCHED — version $VERSION contains the fix (19.4.1+)"
exit 0
else
echo "VULNERABLE — version $VERSION is in the affected range (19.4.0)"
exit 1
fi
fi
# MINOR > 4 on major 19 — should be safe
echo "PATCHED — version $VERSION is beyond all known affected minor releases"
exit 0- GitLab Critical Patch Release 19.4.1, 19.3.3, 19.2.7
- SecurityOnline — GitLab Critical Patch Release Fixes Severe RCE Flaws
- Strix AI — CVE-2026-93577 Analysis
- CVEMon — CVE-2026-93577 Overview & Trends
- ThreatInt — CVE-2026-93577
- DEV Community — Sizing Self-Managed GitLab Exposure (Shodan/Censys)
- CISA Known Exploited Vulnerabilities Catalog
- FIRST EPSS — Exploit Prediction Scoring System
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.