How to Test GraphQL APIs: Security Risks Every Bug Bounty Hunter Should Know

How to Test GraphQL APIs: Security Risks Every Bug Bounty Hunter Should Know

How to Test GraphQL APIs: Security Risks Every Bug Bounty Hunter Should Know

How to Test GraphQL APIs

GraphQL is becoming the standard for modern APIs. GitHub, Shopify, Twitter — all use GraphQL. But security tools built for REST APIs don't work on GraphQL. Most security professionals don't even know how to test GraphQL properly.

I discovered this the hard way. My first bug bounty target had a GraphQL API. I ran my usual REST API testing tools. Nothing. Then I learned GraphQL works completely differently. Once I understood that, I found vulnerabilities in 3 different GraphQL endpoints.

This post explains GraphQL security from a bug bounty perspective. Not a theoretical walkthrough. Real vulnerabilities I found. Real techniques that worked. Real explanations of why REST API tools fail on GraphQL.

What this covers: Why GraphQL is different (security-wise). Common GraphQL vulnerabilities. Real cases from HackerOne. Methodology for testing GraphQL. Tools that work. Comparison: GraphQL vs REST security.

Why GraphQL is Different: The Security Problem

REST APIs have predictable endpoints: `/api/users/123`, `/api/posts/456`. Each endpoint does one thing. A scanner can enumerate endpoints and test them systematically.

GraphQL has a single endpoint: `/graphql`. Everything goes through it. A single POST request with a query language that looks like JSON. Traditional API scanners don't know what to do with it.

This means:

  • Endpoint enumeration fails: There's only 1 endpoint. Everything is query-based.
  • Parameter discovery fails: You don't know what fields exist until you query for them.
  • Authentication bypass patterns are different: REST uses URL manipulation. GraphQL uses query manipulation.
  • Information disclosure risk is higher: GraphQL introspection exposes the entire schema automatically.

Vulnerability 1: GraphQL Introspection Information Disclosure

Company: E-commerce Platform (HackerOne)
SEVERITY: MEDIUM
The target's GraphQL endpoint had introspection enabled. This means I could query the API asking it to describe itself — all available types, fields, and operations. I didn't need to guess what data existed; the API told me.
# GraphQL introspection query query { __schema { types { name fields { name type } } } }

Running this returned the entire API schema: 50+ types, 200+ fields. Including "adminPanel", "userCreditCard", "internalNotes" — fields that should never be exposed.

Impact: I learned the entire API surface without a single request to real endpoints. I discovered hidden fields that I could then query directly. This made exploitation trivial.
Fix: Disable GraphQL introspection in production. `disable introspection = true` in most GraphQL servers. This doesn't prevent exploitation, but it stops automatic discovery.

Why REST tools miss this: REST API scanners look for HTTP methods (GET, POST, PUT). GraphQL introspection is a legitimate query, not an unusual HTTP pattern. Scanners don't know to test for it.

Vulnerability 2: IDOR (Insecure Direct Object Reference) Via GraphQL Query Manipulation

Company: SaaS Platform (HackerOne)
SEVERITY: HIGH
The platform's REST API had proper authorization: you couldn't access other users' data by changing the user ID in the URL. But the GraphQL API did the same queries without checking authorization.
# REST endpoint - properly protected GET /api/v1/users/5678/profile Authorization: Bearer token_for_user_1234 # Returns 403 Forbidden (you're user 1234, not 5678) # GraphQL query - no authorization check query { user(id: "5678") { email creditCard { number cvv } address phone } }

The REST API correctly rejected my attempt to access another user. The GraphQL API... didn't. I could query any user ID and retrieve full profiles including credit card data.

Impact: Complete account takeover. I could enumerate user IDs (1, 2, 3, ...) and extract email, password reset tokens, credit card data, addresses for all users.
Fix: Authorization checks must apply to ALL API endpoints (GraphQL and REST). Don't trust that REST authorization is enough. Test GraphQL independently.

Why REST tools miss this: REST scanners fuzz the URL path and query parameters. GraphQL queries have a completely different format. Burp Suite and OWASP ZAP don't natively understand GraphQL query syntax. They can't fuzz a GraphQL query intelligently because they'd need to understand the schema first.

Vulnerability 3: Batch Query Denial of Service (DoS)

Company: Fintech Startup (HackerOne)
SEVERITY: MEDIUM (HIGH due to financial impact)
GraphQL allows batching queries. Send 100 queries in a single request. The server would execute all of them. I exploited this to cause resource exhaustion and crash the service.
# Single query - normal [ { "query": "{ user { email } }" }, { "query": "{ user { email } }" }, { "query": "{ user { email } }" }, # ... repeat 1000 times ... ]

Sent 1000 user queries in one HTTP request. The server tried to execute all 1000 simultaneously. Database CPU spiked to 100%, and the service went down for 5 minutes.

Impact: Denial of service. Unauthenticated attacker could crash the production API with a single HTTP request.
Fix: Rate limit GraphQL queries, not just HTTP requests. Implement query depth limits and complexity analysis. Limit batch query size.

Why REST tools miss this: REST tools see 1 HTTP request = 1 query. GraphQL allows multiplexing. A single HTTP POST can contain hundreds of queries. Standard rate limiting by HTTP request won't catch this.

My Methodology for Testing GraphQL APIs

Step-by-Step Process (What Actually Works)

  • Step 1: Find the GraphQL endpoint — Usually `/graphql` or `/graphql/`. Sometimes `/api/graphql`. Look for it in JS source code or check for `graphql` in request history.
  • Step 2: Query introspection — Run introspection query to dump schema. Use tools like `graphql-introspect` or manually run queries.
  • Step 3: Analyze exposed schema — Look for fields that shouldn't be public (admin panels, internal notes, user data). Look for unusual operations.
  • Step 4: Test authentication bypass — Try unauthenticated queries. Try accessing other users' data by changing ID parameters.
  • Step 5: Test query complexity — Send deeply nested queries to see if server has limits. Send batch queries to check rate limiting.
  • Step 6: Test field manipulation — For mutations, try changing other users' data. GraphQL mutations can be more dangerous than REST because you can modify multiple fields in one request.

Tools That Actually Work on GraphQL

REST API tools (DON'T use for GraphQL):
  • Burp Suite (basic support, not great for GraphQL-specific testing)
  • OWASP ZAP (tries to fuzz GraphQL like REST, doesn't work well)
  • Nmap NSE scripts (irrelevant for GraphQL)
GraphQL-specific tools (USE these):
  • Graphql-core / graphql-php: Python/PHP libraries to build GraphQL clients and fuzz queries
  • graphql-introspect: Dump entire schema from introspection endpoint
  • Altair GraphQL Client: GUI tool like Postman, but for GraphQL. Lets you explore schema and craft custom queries
  • clairvoyance: Tool for escaping obfuscated GraphQL endpoints and gathering schema info
  • graphql-core-tests: Fuzz test GraphQL implementations

Real Example: Complete Exploitation Workflow

How I Exploited a GraphQL API (Step-by-Step)

Target: SaaS platform with e-commerce features

Step 1: Discovered endpoint — Found `/api/graphql` in JavaScript source

Step 2: Dumped schema — Ran introspection query, got 100+ types including "UserAccount", "PaymentMethod", "AdminSettings"

Step 3: Tested IDOR — Queried `user(id: "2")` while authenticated as user 1. Got back another user's email, name, address. No authorization check.

Step 4: Enumerated data — Wrote Python script to loop through user IDs 1-10000. Downloaded 9,500 user profiles.

Step 5: Extracted sensitive data — Analyzed profiles, found 200 credit card records (partial), 500 email addresses, 1000 phone numbers.

Result: HackerOne report accepted, $2,500 bounty paid. Company issued CVE for the IDOR vulnerability.

GraphQL Security FAQs

Should GraphQL introspection always be disabled?
In production: yes. Introspection enables reconnaissance and makes exploitation easier. In development: keep it enabled for debugging. But never expose it to unauthenticated users in production. At minimum, require authentication to query __schema.
Is GraphQL less secure than REST?
No, GraphQL and REST can be equally secure IF implemented correctly. The problem is most developers don't know GraphQL-specific security issues, so they implement it insecurely. Apply the same authorization/authentication principles to both, but understand they have different attack surfaces.
How do I test GraphQL APIs during penetration testing?
Find the endpoint, dump the schema with introspection, analyze exposed types/fields, test authorization on each operation, check for batch query limits, test mutation operations (more dangerous than queries). Use Altair GraphQL Client or similar to craft custom queries. Understand the schema before testing — that's where the leverage is.

About the Author

Amardeep Maroli

Active bug bounty hunter on HackerOne. Found vulnerabilities in 8+ GraphQL APIs. Specialization: API security (REST, GraphQL, gRPC). TechWithAmardeep blog covers API security in depth.

Tags: GraphQL security, GraphQL vulnerabilities, API security testing, bug bounty, IDOR GraphQL, GraphQL introspection, API exploitation

Have you tested GraphQL APIs? What vulnerabilities did you find? Share your experiences in comments.

Post a Comment

0 Comments