GraphQL Injections
Data query and manipulation language for APIs
Core Concepts
Uses
HTTP/HTTPS, typically overPOSTrequests.JSON-based queries and responses.Typically uses a single endpoint for all operations.
Apollo Servercommonly usesport 4000as its default when started without configuration.Express-based GraphQL serversfrequently useport 3000, simply because that's the default for many Express setups.Introspectionallows clients to query the API schema for available operations and data types.
Schema
Every GraphQL API has a schema that defines:
Types- What objects existQueries- How to READ dataMutations- How to WRITE/CHANGE data
Types
A Type defines the structure of an object:
type User {
id: ID!
email: String!
role: String!
inviteCode: String
verified: Boolean!
}This means:
Useris an objectIt has 5 fields:
id,email,role,inviteCode,verified!means required/non-nullNo
!means optional (can be null)
Queries
Queries are like GET requests in REST:
type Query {
me: User
systemStatus: String
incidentReports: [IncidentReport]
}query {
me {
id
email
}
}When a query returns an OBJECT type (like User), you must specify which fields you want. You can't just say me , you must say me { id email }
Mutations
Mutations are like POST/PUT/DELETE in REST:
type Mutation {
login(email: String!, password: String!): User
register(email: String!, password: String!): User
regenerateInviteCode: User
}mutation {
login(email: "test@test.com", password: "pass123") {
id
email
verified
}
}logintakes 2 arguments:emailandpasswordIt returns a
UserobjectWe specify which User fields we want back:
id,email,verified
Introspection
introspection allow to query the schema itself.
If introspection is enabled in production, attackers can discover the entire API structure.
The GraphQL Request Format
Every GraphQL request has this structure:
{
"query": "your GraphQL query here",
"variables": { "optional": "values" }
}Testing Checklist
Key GraphQL Security Issues
Introspection in Production
Over-fetching Sensitive Data
Mutation Side Effects
Test Query Depth and Complexity: Check server limits on nested or complex queries to prevent performance issues.Validate Input Types and Arguments: Test inputs with invalid data to identify validation weaknesses.Examine Query Aliasing and Batching: Test for data leaks via aliased queries and batched requests.Check for Introspection Misuse: Ensure introspection doesn't expose sensitive or unnecessary schema details.Assess Authorization Controls: Confirm proper enforcement of access controls for queries and operations.Evaluate Rate Limiting: Ensure the API handles excessive or malicious requests effectively.Fuzz Mutations: Test for security and validation flaws in mutation operations.
Introspection Queries
For Burp Suite, wrap the queries in JSON.
Discovery
Intelligence Gathering
Attack Preparation
Understand exactly what data you need to send to execute an attack
You cannot hack a mutation without knowing what arguments it accepts.
Once you find a query that returns a
User, run this to see if it contains sensitive fields that you can request.
Response Analysis
Determine if you can dump data in bulk (Lists) or if you get detailed objects
If a mutation returns a
Userobject, you might be able to ask for private user data immediately after creating/updating them.
If you find a query that returns a type of
kind: LIST(e.g.,[User]), you can potentially ask for every user in the database in a single request, rather than just one.
Executing Mutations
Once you have found a Mutation name and its required Arguments, use these templates to attack it.
Mutation with NO Arguments
Use this when the mutation acts on the current logged-in user (like regenerateInviteCode or logout).
Mutation with INLINE Arguments
Use this for simple mutations (like login or deleteUser) where you have hard-coded values.
Remember to escape quotes (
\") if you are inside aJSONstring.
Mutation with VARIABLES
It separates the logic from the data, making it much easier to fuzz specific parameters.
The
querypart: Defines what you are doing and types of data (String!).The
variablespart: Contains the actual payload.
Last updated