Hacking GraphQL — Part 1
In part 1 of the Hacking GraphQL series, we’re going to discuss the basics of GraphQL and how adversaries can exploit this service.

What is GraphQL?
In simple words, GraphQL is a query language for API endpoints. It interacts with API endpoints and fetches data from the backend. It’s an alternative for API standards like REST and SOAP. It can do most of the things that standard REST API endpoints can do and sometimes even more in an efficient and controlled manner.
GraphQL solves a lot of the problems that developers face when working with the REST API, like fetching more data than what’s needed or the need to have a new endpoint for every call.
Excerpt from the official documentation:
GraphQL is a query language for your API, and a server-side runtime for executing queries using a type system you define for your data. GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.
Sample GraphQL Query:

Type of Requests:
There are 2 main request types in GraphQL — Query and Mutation.
Query: A Query is used to read data.
{
"data":{
"todos":[
{
"title": "Learn GraphQL"
},
{
"title": "Learn about queries"
}
]
}
}
The query and the response have a similar format, demonstrating that you’ll get what you ask for in GraphQL. For instance, in the code block above, we queried for the title. This means that we’ll get the title in the subsequent response.
Mutation: A Mutation is used to insert, update, or delete the data.
mutation{
insert_todos(objects:[{title:"Learn GraphQL"}]){
Returning{
Id
Created_at
}
}
}
For instance, the screenshot above depicts a mutation that adds a new Todo note. If successful it will return the id and the creation date of the newly inserted Todo note.
Some common GraphQL endpoints:
It’s difficult to list all endpoints in a GraphQL instance but many implementations use a framework like ‘Appollo’. The following section lists common endpoints used in GraphQL implementations:
- /v1/*
- /v2/*
- /beta/*
- /graph
- /graphql
- /graphql/console
- /graphql.php
- /graphiql
- /graphiql.php
GraphQL Schema:
A GraphQL schema is at the core of any GraphQL server implementation. It describes the functionality available to clients that connect to the GraphQL instance. It’s like a blueprint that clients can learn by querying for it.
Introspection:
To get the schema we can send an HTTP request to the GraphQL server endpoint asking for the GraphQL schema. This type of HTTP request is called a GraphQL introspection query.
Introspection is the main ability to query which resources are available in the schema. With introspection, we can see the queries, types, fields, and directives it supports. The introspection query is unfortunately turned on by default, so it is worth trying during a penetration test.

How to send an introspection query?
The introspection query gives us details about queries, types, fields, and directives that are supported by GraphQL and by default we can use the introspection query on every GraphQL instance. Let’s look at an introspection query in action.
Step 1: Intercept the HTTP request using Burp Suite:

Step 2: Send the HTTP request to Burp Repeater:

Step 3: Replace the POST body with a generic introspection query to fetch the entire backend schema. For this, we have used the ‘GraphQL Raider’ extension of Burp Suite.

Step 4: Capture the schema to gather sensitive API calls.

Sample Introspection Query:
{"query":"\n query IntrospectionQuery {\r\n __schema {\r\n queryType { name }\r\n mutationType { name }\r\n subscriptionType { name }\r\n types {\r\n ...FullType\r\n }\r\n directives {\r\n name\r\n description\r\n locations\r\n args {\r\n ...InputValue\r\n }\r\n }\r\n }\r\n }\r\n\r\n fragment FullType on __Type {\r\n kind\r\n name\r\n description\r\n fields(includeDeprecated: true) {\r\n name\r\n description\r\n args {\r\n ...InputValue\r\n }\r\n type {\r\n ...TypeRef\r\n }\r\n isDeprecated\r\n deprecationReason\r\n }\r\n inputFields {\r\n ...InputValue\r\n }\r\n interfaces {\r\n ...TypeRef\r\n }\r\n enumValues(includeDeprecated: true) {\r\n name\r\n description\r\n isDeprecated\r\n deprecationReason\r\n }\r\n possibleTypes {\r\n ...TypeRef\r\n }\r\n }\r\n\r\n fragment InputValue on __InputValue {\r\n name\r\n description\r\n type { ...TypeRef }\r\n defaultValue\r\n }\r\n\r\n fragment TypeRef on __Type {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n ","variables":null}
The response may be quite big and hard to understand. The best way to understand the response is to visualize it. This can be done by using the ‘Voyager’ tool.

To get the same result as above, perform an introspection query on the target and paste the response in the ‘Voyager’ tool. Using this method, attackers can easily identify sensitive API calls and exploit them.
We will be exploring more attack vectors in the Hacking GraphQL — Part 2.
Stay safe, stay healthy and hack responsibly.
Connect with us: Website, LinkedIn, Twitter, Facebook.
References:
https://graphql.org/learn
https://portswigger.net/burp
https://apis.guru/graphql-voyager
https://github.com/portswigger/graphql-raider
Redfox Security is a diverse network of expert security consultants with a global mindset and a collaborative culture. With a combination of data-driven, research-based, and manual testing methodologies, we proudly deliver robust security solutions.
“Join us on our journey of growth and development by signing up for our comprehensive courses, if you want to excel in the field of cybersecurity.”