← Back to Feed CACHED · 2026-08-18 09:29:17 · CACHE_KEY CVE-2026-19650
CVE-2026-19650 · CWE-352 · Disclosed 2026-08-17

GitLab has remediated an issue in GitLab CE/EE affecting all versions from 18.2 before 18.11.11

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

Someone left the back door of the code factory on a spring latch — any developer who clicks a link swings it wide open

CVE-2026-19650 is a cross-site request forgery (CSRF) flaw in GitLab CE/EE's GraphQL multiplex query handler. The root cause is that the /api/graphql endpoint fails to enforce CSRF token validation when mutations are submitted as GET requests through the multiplex path, bypassing the POST+X-CSRF-Token requirement that normally gates state-changing operations. An attacker crafts a malicious URL or page; when an authenticated GitLab user visits it, the browser fires off GraphQL mutations — creating snippets, modifying project settings, or potentially altering CI/CD pipeline configurations — under the victim's session. Affected versions span 18.2 through 18.11.10, 19.0.0–19.0.7, 19.1.0–19.1.5, and 19.2.0–19.2.3. That is roughly 18 months of release trains.

GitLab rates this HIGH / 7.1, which is *directionally correct* but slightly understates the blast radius. The CVSS vector (AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L) captures the social-engineering prerequisite and the integrity impact, but it treats GitLab like a generic web app. In reality, GitLab is the CI/CD control plane: mutations against it can alter .gitlab-ci.yml, inject pipeline steps, exfiltrate CI/CD variables, or modify deploy-key ACLs. That supply-chain multiplier pushes the effective risk above 7.1 for any org running self-managed GitLab with privileged maintainers. noisgate nudges this to 7.5 HIGH.

"CSRF in GitLab GraphQL lets attackers fire mutations via GET — on a CI/CD platform, that's supply-chain risk."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Craft malicious GraphQL multiplex GET URL

The attacker constructs a URL targeting /api/graphql with a multiplex query payload containing one or more mutations encoded as GET parameters. Because the multiplex handler does not enforce CSRF token validation on GET-submitted mutations, this payload will be accepted server-side if accompanied by a valid session cookie. No authentication or GitLab account is needed by the attacker.
Conditions required:
  • Knowledge of victim's GitLab instance hostname
  • Understanding of the GraphQL multiplex parameter format
Where this breaks in practice:
  • Attacker must know or guess the target GitLab instance URL — trivial for public instances, slightly harder for internal ones
Detection/coverage: WAF rules inspecting /api/graphql GET requests for mutation keywords (mutation {, Mutation) can flag anomalous traffic.
STEP 02

Social-engineer victim into clicking the link

The attacker delivers the crafted URL via phishing email, Slack message, issue comment, or embedded <img> / <iframe> tag on a page the victim will visit. The victim must be authenticated to the target GitLab instance with an active session cookie. No additional credentials are harvested — the browser supplies the session automatically.
Conditions required:
  • Victim must have an active authenticated session on the target GitLab instance
  • Victim must click the link or load the page containing the payload
Where this breaks in practice:
  • Requires successful social engineering — conversion rates vary, typically 5–15% in targeted campaigns
  • SameSite cookie policies (Lax by default in modern browsers) may block cross-site GET requests carrying cookies for some mutation types, though navigation-level GETs are generally exempt from SameSite=Lax
Detection/coverage: Email security gateways and link scanners can detect URLs with GraphQL query payloads. Browser-based CSP form-action directives on the attacker's site are irrelevant — this is a direct navigation.
STEP 03

Mutations execute under victim's identity

The GraphQL multiplex handler processes the GET request and executes the embedded mutations with the victim's full permissions. Depending on the victim's role, this could range from creating a snippet (Developer) to modifying project CI/CD variables, adding deploy keys, or changing project visibility (Maintainer/Owner). The mutations are logged in GitLab's audit log but attributed to the victim, not the attacker.
Conditions required:
  • Victim has sufficient GitLab permissions for the targeted mutation
Where this breaks in practice:
  • Impact is bounded by the victim's role — phishing a Guest-level user yields minimal damage
  • GitLab audit logs will record the mutations, enabling post-incident forensics
Detection/coverage: GitLab audit events for project settings changes, CI/CD variable modifications, and deploy key additions. SIEM correlation of unusual mutation volume from a single user session.
STEP 04

Supply-chain pivot via CI/CD manipulation

If the victim is a Maintainer or Owner, the attacker can use mutations to modify .gitlab-ci.yml include references, inject malicious pipeline steps, or exfiltrate masked CI/CD variables by creating a new pipeline configuration that echoes them. This turns a CSRF into a supply-chain compromise vector — malicious code enters the build pipeline and ships to production.
Conditions required:
  • Victim must be a Maintainer or Owner on a project with active CI/CD pipelines
  • CI/CD variables must not be restricted to protected branches only
Where this breaks in practice:
  • Organizations using protected branches and requiring MR approvals add a gate between the mutation and code execution
  • Pipeline changes trigger notifications and are visible in merge request diffs
Detection/coverage: Pipeline modification alerts, CI/CD variable access logs, GitLab Duo or third-party CI security tools monitoring for unexpected pipeline changes.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo confirmed exploitation. Not listed on CISA KEV. No campaign reports from Mandiant, CrowdStrike, or threat intel feeds as of 2026-08-18.
Proof-of-ConceptThe underlying CSRF-via-GET pattern was publicly demonstrated in HackerOne #1122408 by researcher az3z3l (2021) and expanded by kreep for the multiplex handler variant. The original PoC created snippets; the multiplex variant likely extends to arbitrary mutations. No weaponized exploit toolkit observed.
EPSS ScoreNot yet scored (disclosed 2026-08-17). Expect initial EPSS in the 0.05–0.15 range given the UI:R requirement and lack of automation-friendly exploitation.
KEV StatusNot listed. No CISA KEV entry as of 2026-08-18.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L — Network-reachable, low complexity, no privileges needed, but requires user interaction. High integrity impact, low availability, no confidentiality impact. The C:N is misleading if mutations can exfiltrate CI/CD variables indirectly.
Affected VersionsGitLab CE/EE 18.2 – 18.11.10, 19.0.0 – 19.0.7, 19.1.0 – 19.1.5, 19.2.0 – 19.2.3. ~18 months of releases.
Fixed Versions18.11.11, 19.0.8, 19.1.6, 19.2.4 (released 2026-08-17). GitLab.com and GitLab Dedicated already patched.
Exposure SurfaceCensys and Shodan historically show 50,000–80,000 internet-facing self-managed GitLab instances. Many enterprises also run GitLab on internal networks reachable via VPN, expanding the CSRF attack surface to any developer who clicks a link while connected.
Disclosure Date2026-08-17 via GitLab critical patch release.
ReporterSecurity researcher kreep via GitLab's HackerOne bug bounty program.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (7.5/10)

The single most decisive factor is the role multiplier: GitLab is canonically a CI/CD platform, and CSRF-driven mutation execution against a Maintainer ends in supply-chain compromise — injecting malicious pipeline steps that ship to production. The UI:R prerequisite provides real friction but does not overcome this blast-radius floor.

HIGH Vulnerability mechanics and affected versions
MEDIUM Full mutation scope exploitable via multiplex GET path
LOW EPSS and real-world exploitation likelihood

Why this verdict

  • User interaction is real friction but not a blocker. Phishing a GitLab developer or maintainer is well within commodity attacker capability — targeted campaigns against devops teams routinely achieve 5–15% click rates. The UI:R reduces mass exploitation but does not prevent targeted attacks.
  • Role multiplier — CI/CD control plane. GitLab is not a generic web app; it is the build and deploy pipeline. Mutations that modify CI/CD variables, inject pipeline steps, or alter deploy keys have supply-chain-scale blast radius. This is the canonical high-value role (CI/CD + artifact stores) from the role catalog, meaning ≥10% of GitLab installs occupy this role by definition — the verdict floor is HIGH.
  • Wide affected version range. Spanning 18.2 through 19.2 (~18 months of releases) means most self-managed instances are vulnerable unless they upgraded on patch day. Combined with 50K–80K internet-facing instances, the exposure population is substantial.
  • SameSite cookie behavior provides partial mitigation. Modern browsers default to SameSite=Lax, which blocks cross-site subrequests but permits top-level navigation GETs — exactly the vector this CSRF uses. SameSite=Lax does NOT stop this attack for navigation-triggered GET requests.

Why not higher?

This is not CRITICAL because exploitation requires successful social engineering of an authenticated user — it cannot be automated at scale like a pre-auth RCE. The CVSS scope is Unchanged (S:U), meaning the attacker cannot escape the victim's permission boundary. An attacker who phishes a low-privilege user gets minimal impact. The chain only reaches supply-chain severity when the victim is a Maintainer/Owner, which narrows the high-impact target set.

Why not lower?

GitLab is a CI/CD platform by definition — the supply-chain blast radius when a Maintainer is targeted sets a HIGH floor that friction alone cannot breach. The affected version range is exceptionally wide (18 months), the exposure surface includes tens of thousands of internet-facing instances, and the CSRF pattern (GET-based mutation via multiplex) requires no attacker authentication or complexity. Dropping to MEDIUM would ignore the canonical high-value role of the affected component.

05 · Compensating Control

What to do — in priority order.

  1. Restrict GraphQL API access via reverse proxy — Configure your reverse proxy (nginx, HAProxy, Cloudflare) to block GET requests to /api/graphql that contain mutation in query parameters. This surgically kills the CSRF vector without breaking normal GraphQL POST operations. Deploy within the noisgate mitigation SLA of 30 days for HIGH findings.
  2. Enforce SameSite=Strict on GitLab session cookies — Override GitLab's session cookie SameSite attribute to Strict at the load balancer or reverse proxy level. This prevents cross-site navigation from sending session cookies, fully neutralizing the CSRF. Note: this will break legitimate cross-site login flows (OAuth redirects) — test thoroughly before deploying.
  3. Scope CI/CD variables to protected branches only — Ensure all sensitive CI/CD variables are marked as *protected* and scoped to protected branches. This limits what a CSRF-driven pipeline injection can exfiltrate, even if the attacker modifies an unprotected branch's .gitlab-ci.yml.
  4. Enable GitLab audit event streaming to SIEM — Stream GitLab audit events for project settings changes, CI/CD variable modifications, pipeline configuration changes, and deploy key additions to your SIEM. Alert on unusual mutation patterns to catch exploitation attempts post-click.
What doesn't work
  • Network-level IP allowlisting for GitLab — the CSRF executes from the victim's browser, which is already on the trusted network. IP restrictions do not help because the request originates from an authorized source.
  • MFA on GitLab login — MFA protects the authentication ceremony but not an already-authenticated session. Once the user is logged in, the CSRF rides the existing session cookie.
  • Content Security Policy on GitLab — CSP on the *GitLab instance* does not prevent a CSRF originating from an *external* attacker-controlled page. CSP would need to be on the attacker's page, which the attacker controls.
06 · Verification

Crowdsourced verification payload.

Run this script on any host with curl and network access to your GitLab instance. Invoke as: ./check_cve_2026_19650.sh https://gitlab.example.com. No authentication needed — it checks the GitLab version via the public API.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_19650.sh — Check GitLab instance for CVE-2026-19650
# Usage: ./check_cve_2026_19650.sh <GITLAB_URL>
# Requires: curl, awk
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -euo pipefail

if [ $# -lt 1 ]; then
  echo "Usage: $0 <GITLAB_URL>"
  exit 2
fi

GITLAB_URL="${1%/}"

# Fetch version from public API (no auth required if version API is exposed)
VERSION=$(curl -sf "${GITLAB_URL}/api/v4/version" 2>/dev/null | grep -oP '"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' || true)

if [ -z "$VERSION" ]; then
  # Try metadata endpoint as fallback
  VERSION=$(curl -sf "${GITLAB_URL}/api/v4/metadata" 2>/dev/null | grep -oP '"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' || true)
fi

if [ -z "$VERSION" ]; then
  echo "UNKNOWN — could not retrieve GitLab version from ${GITLAB_URL}"
  echo "The /api/v4/version endpoint may require authentication."
  echo "Manually check: Settings > Help > GitLab version"
  exit 2
fi

echo "Detected GitLab version: $VERSION"

MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)

VULNERABLE=0

# Affected: 18.2.0 - 18.11.10
if [ "$MAJOR" -eq 18 ] && [ "$MINOR" -ge 2 ]; then
  if [ "$MINOR" -lt 11 ]; then
    VULNERABLE=1
  elif [ "$MINOR" -eq 11 ] && [ "$PATCH" -lt 11 ]; then
    VULNERABLE=1
  fi
fi

# Affected: 19.0.0 - 19.0.7
if [ "$MAJOR" -eq 19 ] && [ "$MINOR" -eq 0 ] && [ "$PATCH" -lt 8 ]; then
  VULNERABLE=1
fi

# Affected: 19.1.0 - 19.1.5
if [ "$MAJOR" -eq 19 ] && [ "$MINOR" -eq 1 ] && [ "$PATCH" -lt 6 ]; then
  VULNERABLE=1
fi

# Affected: 19.2.0 - 19.2.3
if [ "$MAJOR" -eq 19 ] && [ "$MINOR" -eq 2 ] && [ "$PATCH" -lt 4 ]; then
  VULNERABLE=1
fi

if [ "$VULNERABLE" -eq 1 ]; then
  echo "VULNERABLE — GitLab $VERSION is affected by CVE-2026-19650"
  echo "Upgrade to 18.11.11, 19.0.8, 19.1.6, or 19.2.4"
  exit 1
else
  echo "PATCHED — GitLab $VERSION is not affected by CVE-2026-19650"
  exit 0
fi
07 · Bottom Line

If you remember one thing.

TL;DR
Patch self-managed GitLab to 18.11.11, 19.0.8, 19.1.6, or 19.2.4 this month. This is a HIGH finding under the noisgate framework — your noisgate mitigation SLA is 30 days: deploy the reverse-proxy GET-mutation block or SameSite=Strict cookie override as a compensating control while you schedule the upgrade. Your noisgate remediation SLA is 180 days for the actual patch, but given this is a one-day-old disclosure with a wide blast radius across 18 months of GitLab releases, aim to have the vendor patch applied within 30 days alongside the mitigation. Prioritize instances where Maintainer/Owner-level users are active — those are your supply-chain-risk nodes. If you run GitLab.com or GitLab Dedicated, you are already patched and no action is needed.

Sources

  1. GitLab Critical Patch Release 19.2.4, 19.1.6, 19.0.8, 18.11.11
  2. The Hacker News — Critical GitLab GraphQL Flaw Coverage
  3. Tenable — CVE-2026-19650
  4. CyberPress — GitLab Critical Vulnerability Analysis
  5. GitLab Issue #324397 — CSRF on /api/graphql via GET Mutations
  6. CSA Singapore — Multiple Vulnerabilities in GitLab Products
  7. GitLab Forum — Critical Patch Release Announcement
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.