GraphQL Security
GraphQL misconfigurations — enabled introspection, missing query depth limits, and unlimited batching — expose your entire API schema to attackers and enable resource exhaustion attacks that can take down your server with a single query.
What Is GraphQL Security?
GraphQL's flexibility — letting clients request exactly the data they need — also makes it a uniquely powerful attack surface. Three misconfigurations that are on by default in most GraphQL libraries create serious security risks in production.
Vulnerability 1 — Introspection Enabled
GraphQL introspection is a built-in feature that lets clients query the entire API schema: every type, field, query, mutation, and their relationships.
# Attacker sends this query
{
__schema {
types {
name
fields {
name
type { name }
}
}
}
}Response reveals your complete data model — every table, relationship, and operation. This dramatically reduces the work an attacker needs to do to find targets.
Why it matters for AI-generated apps: AI tools enable introspection by default in every GraphQL library (Apollo, Strawberry, Hasura, Pothos). Developers rarely disable it before launch.
Vulnerability 2 — No Query Depth Limiting
GraphQL allows deeply nested queries. Without depth limiting:
# Resource exhaustion — O(n^depth) database queries
{
users {
friends {
friends {
friends {
friends {
# ... 20 levels deep
name email posts { comments { author { friends { name } } } }
}
}
}
}
}
}A single query from a single unauthenticated client can exhaust your database connection pool and bring down the server.
Vulnerability 3 — Unlimited Query Batching
GraphQL supports sending multiple queries in one request:
[
{"query": "{ user(id: 1) { password } }"},
{"query": "{ user(id: 2) { password } }"},
... 1000 more queries ...
]This bypasses rate limits (1 HTTP request = 1000 GraphQL operations), enables brute-force on per-field resolvers, and can be used to enumerate data at scale.
Real-World Impact
- Full schema exposure — attackers map every field including sensitive ones (
password_hash,ssn,credit_card) - DoS — one deeply nested query exhausts server resources
- Rate limit bypass — brute-force or enumeration via batch queries
- Data extraction — batch queries extract all user data faster than REST enumeration
How to Fix
Disable introspection in production:
# Strawberry (Python)
schema = strawberry.Schema(
query=Query,
mutation=Mutation,
extensions=[DisableIntrospection] if not settings.DEBUG else []
)// Apollo Server
const server = new ApolloServer({
schema,
introspection: process.env.NODE_ENV === 'development',
})Add query depth limiting:
// graphql-depth-limit
import depthLimit from 'graphql-depth-limit'
const server = new ApolloServer({
schema,
validationRules: [depthLimit(7)] // max 7 levels deep
})# Strawberry — custom extension
from strawberry.extensions import AddValidationRules
from graphql import GraphQLError
def max_depth_rule(max_depth: int):
def rule(validation_context):
# ... depth checking implementation
return rule
schema = strawberry.Schema(extensions=[AddValidationRules([max_depth_rule(7)])])Limit query complexity and disable batching:
// Apollo — complexity limiting
import { createComplexityRule } from 'graphql-query-complexity'
validationRules: [
createComplexityRule({ maximumComplexity: 1000, variables: {} })
]
// Disable batching
const server = new ApolloServer({
allowBatchedHttpRequests: false, // Apollo 4+
})What VibeWShield Detects
VibeWShield's GraphQL Security scanner tests discovered GraphQL endpoints (/graphql, /gql, /api/graphql) for:
- Introspection enabled — sends
{__schema{types{name}}}and checks for schema response - No query depth limit — sends a 10-level deep nested query and checks if it resolves
- Unlimited batching — sends 100 queries in one batch request and checks if all succeed
Findings are flagged as Medium (introspection) to High (batching bypass, DoS via depth) with the exact query and response as evidence.
Free security scan
Test your app for GraphQL Security
VibeWShield automatically checks for GraphQL Security and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.
Scan your app free