What are the main security risks specific to GraphQL APIs, and how do you mitigate them?
GraphQL's flexibility — letting clients specify exactly what data they want and how deeply to traverse relationships — is also its security challenge.
Key risks:
-
Introspection exposure: by default, GraphQL exposes a full schema introspection endpoint. An attacker can query
__schemato enumerate all types, fields, and mutations — effectively getting a map of your data model and attack surface. Disable introspection in production (or restrict it to authenticated/internal users). -
Query depth/complexity attacks (DoS): a deeply nested query like
{ user { friends { friends { friends { posts { ... } } } } } }can trigger exponential DB joins. Enforce maximum query depth (e.g. 5–7 levels) and query complexity limits (assign a cost to each field, reject above a budget). -
Batching attacks: GraphQL allows batching multiple queries in one request, or aliasing the same field with different arguments. An attacker can brute-force a login field by sending 100 password attempts in a single HTTP request, bypassing per-request rate limits. Rate limit at the operation level, not just per HTTP request.
-
Object-level authorization (BOLA): GraphQL resolvers must independently check that the authenticated user has access to each resolved object. A query that navigates from a public object to a private one via a relationship field can bypass coarse-grained access control.
-
Injection via field arguments: arguments passed to resolvers can contain SQL/NoSQL injection payloads if not properly parameterized. GraphQL doesn't sanitize inputs — the resolver must.
Mitigations: disable introspection in prod, enforce depth/cost limits (persisted queries for first-party), per-operation rate limiting, field-level authorization in resolvers, input validation.