ShellCodeX
Tools • Events • News • Insights
SEO Checker
← Back to Articles
gitlab detection engineering log analysis graphql siem

Detecting CVE-2026-19478 Exploitation in GitLab GraphQL

When a self‑hosted GitLab project disappears after an unauthenticated GraphQL POST, this guide shows where to look and what rules to run. Includes SIEM queries, Sigma rules and an audit‑event playbook for CVE‑2026‑19478.

How ShellCodeX researches and reviews articles

Detecting CVE-2026-19478 Exploitation in GitLab GraphQL
Detection recipes for GitLab CVE-2026-19478: SIEM queries, Sigma rules, log paths and audit-event hunts to catch unauthenticated GraphQL project deletions.

You wake up to a ticket: a public project’s repository is gone. The web UI shows a 404, the team says no one deleted it. On the GitLab host you find a short spike of POSTs to /api/graphql from a foreign IP and an entry in /var/log/gitlab/gitlab-rails/production.log that records a GraphQL request with a mutation. That behaviour matches the out‑of‑band emergency patch GitLab shipped on August 17, 2026 to fix CVE‑2026‑19478, a critical GraphQL code‑injection issue that can let unauthenticated callers modify or delete public projects (GitLab patch release notes, Aug 17 2026).

Where exploitation leaves traces (logs and events)

An attacker exploiting CVE‑2026‑19478 interacts with the GraphQL endpoint, so traces appear first in your HTTP access and application request logs. At the network edge look for POST requests to /api/graphql (and — for the closely related CVE‑2026‑19650 CSRF weakness — unexpected GETs carrying GraphQL queries). Standard reverse proxies and load balancers log method, path, client IP, request size and headers; those fields are the first pivot for alerting.

On the application host, GitLab’s Rails logs record GraphQL requests in /var/log/gitlab/gitlab-rails/production.log (or production_json.log when JSON logging is enabled). Entries show the request start line, controller (GraphqlController#execute), and a Parameters object that contains the GraphQL document or an operationName. Those log entries often include a short timing line (Completed 200 OK in Xms) that helps build a timeline.

Finally, if the attack succeeds you’ll see administrative footprints: project deletion appears in GitLab audit events (project scope) and may generate repository delete activity in Gitaly logs, Sidekiq job traces, and object‑storage (S3) delete events. The audit events API and CSV/streamed audit schema are the canonical source to confirm who (or what) deleted a project; these require admin privileges to query but are indispensable for attribution.

Concrete log examples you will see

Below are realistic, minimal fragments representative of what a self‑hosted instance will log. They are based on GitLab documentation and community examples of Rails logging for GraphQL requests.

Started POST "/api/graphql" for 203.0.113.45 at 2026-08-19 03:21:12 +0000
Processing by GraphqlController#execute as */*
  Parameters: {"operationName"=>"DeleteProject","variables"=>"[FILTERED]","query"=>"mutation DeleteProject($input: DeleteProjectInput!) { deleteProject(input: $input) { errors } }"}
Completed 200 OK in 82ms (ActiveRecord: 12.3ms | Allocations: 12000)

At the HTTP layer (nginx or load balancer) you will typically see an access entry like this; the logged request body is rarely present, but content length and headers help flag suspicious calls.

203.0.113.45 - - [19/Aug/2026:03:21:12 +0000] "POST /api/graphql HTTP/1.1" 200 512 "-" "curl/7.88.1" "-" "Content-Length: 2048"

If JSON logging is enabled you may also find structured fields such as method, path, params.graphql.query, and remote_ip, which make SIEM detection far easier.

SIEM detection recipes: Splunk, Elastic and a Sigma rule

Detection must be blunt and specific: alert on unauthenticated GraphQL requests that contain destructive keywords, and correlate those requests with subsequent audit events or repository deletions. Below are ready‑to‑paste examples — adapt index and field names to your environment.

Splunk (nginx + rails JSON logs):

index=gitlab_logs (sourcetype=nginx:access OR sourcetype=gitlab:rails_json) (uri_path="/api/graphql" OR path="/api/graphql")
| eval has_auth=if(isnull(http_authorization) OR http_authorization=="",0,1)
| where has_auth=0 AND (searchmatch("mutation") OR searchmatch("delete") OR searchmatch("destroy"))
| stats count by client_ip, user_agent, uri_path, _time

Elastic (Kibana) KQL for combined access + app logs:

http.request.method : "POST" and url.path : "/api/graphql" and (message:*"mutation"* or message:*"delete"* or message:*"destroy"*) and not http.request.headers.authorization : *

Sigma rule (YAML) to deploy to a detection engineering repo — this looks for unauthenticated GraphQL mutations containing destructive verbs. Paste into your Sigma pipeline and tune fields:

title: Detect unauthenticated destructive GraphQL to GitLab
id: 0d9fa3a2-xxxx-4f3d-9a8c-xxxxxxxxxxxx
status: experimental
description: Detect POSTs to /api/graphql with mutation payloads that include delete/destroy keywords and no Authorization header
author: ShellCodeX
logsource:
  product: webserver
  service: gitlab
detection:
  selection:
    Path|contains: "/api/graphql"
    Method: POST
  condition: selection and (Payload|contains: "mutation" and (Payload|contains: "delete" or Payload|contains: "destroy" or Payload|contains: "remove")) and not (RequestHeader.Authorization exists)
falsepositives:
  - automated CI tooling that posts GraphQL mutations with credentials
level: high

Notes: parsing request bodies at the proxy is the most reliable way to detect malicious payloads in real time. If your WAF or reverse proxy supports body inspection, add a rule that rejects unauthenticated mutation requests containing deletion verbs.

Hunt playbook and timeline reconstruction

Step 1 — find the initial call. Search your HTTP front‑end logs for POST /api/graphql between the suspected time window. Extract client IP, X‑Forwarded‑For, User‑Agent and request size. If body capture is available, copy the GraphQL document for safe offline analysis.

Step 2 — confirm mutation intent. Search application rails logs (production.log or production_json.log) for GraphqlController entries matching that IP or time. Look for Parameters objects containing GraphQL operationName or a string starting with "mutation" and keywords like delete, destroy or project. If the JSON logs include params.graphql.query you can extract exact mutation names for forensic reporting.

Step 3 — check audit and repository traces. Use the audit events API to list recent project audit events, filtering by time and entity_type=Project. A deletion audit event will have details.target_type or a custom_message noting deletion. Correlate the audit event's ip_address and author_name/id to the GraphQL request. Also check Gitaly logs and object‑storage (S3) delete notifications for matching timestamps to validate data loss.

  1. Query HTTP access logs for /api/graphql (POST/GET).
  2. Extract suspect GraphQL payloads from rails logs or proxy captures.
  3. Pull project audit events via GET /api/v4/audit_events (admin token required).
  4. Correlate with repository storage and backup snapshots to find last clean copy.

Mitigations and practical controls

Immediate: apply GitLab’s out‑of‑band patch (released Aug 17, 2026) or upgrade to the fixed patch release referenced in GitLab’s patch notes. That is the only reliable mitigation for the underlying flaw. If you cannot patch immediately, implement compensating controls: restrict access to self‑managed GitLab’s management endpoints to known IP ranges, disable public project deletion where possible, and add a WAF rule to block unauthenticated POSTs that contain GraphQL mutation/delete keywords.

Longer term: stream audit events to your SIEM (GitLab supports audit streaming and the audit events API). Treat repository delete audit events as high‑priority signals and create automated playbooks that trigger retention checks and object‑storage rollbacks. Limit the exposure of project management APIs: route GraphQL traffic through an authentication enforcement layer when public projects are enabled.

Operational checklist:

  1. Patch GitLab immediately per the vendor release notes.
  2. Deploy the Sigma/Splunk/Elastic detections above and tune false positives.
  3. Enable audit event streaming and retain logs for at least 90 days during active investigations.
  4. Ensure backups and object storage snapshots are healthy and document restore time objectives.

What to do next

If you detect a suspicious GraphQL deletion attempt: isolate the offending IP, rotate any repository or CI tokens used by the targeted project, and run the audit events API to enumerate deletions. If project data is missing, coordinate a restore from the most recent snapshot and preserve logs and affected VM snapshots for incident response. Finally, treat this event as a test for your GitLab hardening playbook: implement WAF body inspection for /api/graphql and add an automated SIEM rule that escalates unauthenticated GraphQL mutation attempts to on‑call engineers.

GitLab published the emergency patch and technical references that describe the issue and fixed versions; consult the GitLab patch release notes and the CVE entries listed below when prioritising upgrades and informing stakeholders.

Sources reviewed

  1. GitLab Critical Patch Release: 19.2.4, 19.1.6, 19.0.8, 18.11.11 (patch notes)
  2. NVD - CVE-2026-19478
  3. Get started with GitLab GraphQL API (GitLab docs)
  4. Audit events API and audit event types (GitLab docs)
Preview