BIPI
BIPI

GraphQL API Attacks: Introspection, Batching, DoS, Authorization Flaws

Cybersecurity

GraphQL pentest techniques covering introspection abuse, query batching, alias-based rate limit bypass, query depth DoS, and authorization gaps at field resolvers.

By Arjun Raghavan, Security & Systems Lead, BIPI · December 22, 2024 · 10 min read

#graphql#api-pentest#introspection#dos#authorization

GraphQL endpoints are tested differently than REST. The schema is the map, and introspection hands you the map if the team forgot to disable it. Once you have the schema, the entire backend object graph is enumerable with one query.

Finding the Endpoint

  • Common paths: /graphql, /api/graphql, /v1/graphql, /query, /graphiql, /playground, /altair
  • Apollo Server defaults to /graphql, Hasura to /v1/graphql, AWS AppSync varies per app
  • Look for content-type application/graphql or graphql-over-http in mobile and SPA traffic
  • GET requests with ?query= also work on many servers, useful for CSRF and cache poisoning

Introspection: The Master Key

If introspection is on, send the standard __schema query and pipe the result into graphql-voyager or InQL for visualization. You now have every type, every field, every argument. Mutations like deleteUser, makeAdmin, or transferFunds are visible. Even if introspection is blocked at the gateway, field suggestions are often enabled, GraphQL servers helpfully respond with did you mean userByEmail when you query userByEmial.

Field Suggestion Leaks

Tools like clairvoyance or graphql-cop pull the schema from suggestions alone in minutes. The fix is disabling both introspection and field suggestions in production, but Apollo, Hasura, and graphql-ruby all leave suggestions on by default in non-development modes.

Authorization at Field Resolvers

  • Authorization in GraphQL must live at resolver level, not just route middleware, every field is its own endpoint
  • Test field-level auth: query { user(id:1) { email phoneNumber ssn passwordHash } } even when user(id) requires auth
  • Nested object traversal: query { post(id:1) { author { email creditCard { number } } }} bypasses resolver checks on parents
  • Mutations often forget per-argument authorization, updateUser(id:2, role:ADMIN) when caller is user 1

Query Batching for Rate Limit Bypass

Most GraphQL servers accept an array of queries in a single HTTP POST. If rate limits are per-request rather than per-operation, batching 100 login attempts into one HTTP call defeats them. Apollo and graphql-yoga both support batching by default, the burpsuite graphql-batch attack plugin automates this.

Aliases for Brute Force

Aliases let you run the same query multiple times with different arguments in one operation. Brute force OTP verification with: a1: verifyOtp(code:0000) a2: verifyOtp(code:0001) up to a9999. One HTTP request, ten thousand attempts. Hackerone disclosed multiple six-figure bounties on this pattern in 2023 and 2024.

GraphQL aliases turn rate-limiting into a polite suggestion. Cap query complexity and alias count at the parser level, not after execution.

Denial of Service via Query Depth

Recursive relations are the killer. If user has friends and friends are users with friends, you can nest user.friends.friends.friends to depth 50 and produce an exponential database join storm. Add aliases and you DoS the backend in milliseconds. Mitigations: max query depth (graphql-depth-limit), query complexity scoring (graphql-cost-analysis), and persisted queries that whitelist documents by hash.

CSRF on GraphQL

  • GraphQL over GET with cookie auth is CSRF-able, just embed the query in an image tag or form
  • Apollo's recommended csrfPrevention setting is opt-in, many older servers do not enable it
  • Content-type text/plain bypass: browsers send simple CORS, no preflight, no protection
  • Test with a minimal HTML form posting to /graphql, if it returns data you have CSRF

Tooling

  1. InQL Scanner, Burp extension that decodes schema and generates queries automatically
  2. clairvoyance for schema reconstruction via suggestions when introspection is off
  3. graphql-cop, fast Python scanner for misconfig and known weaknesses
  4. Altair or GraphQL Playground as the client, easier than crafting POSTs by hand
  5. graphw00f for fingerprinting the GraphQL implementation (Apollo, Hasura, graphene)

Known CVEs and Bounties

  • CVE-2024-32028 graphql-ruby DoS via deep introspection on certain unions
  • Multiple HackerOne reports on Shopify and GitLab in 2024 paying out for alias-based brute force
  • CVE-2023-49559 Apollo Federation gateway query planner bug enabling auth bypass across subgraphs

Hardening Checklist

  • Disable introspection in production, disable field suggestions everywhere except dev
  • Cap query depth, complexity, and alias count at parser stage
  • Persisted queries with allowlists, hash-based, no arbitrary documents in production
  • Resolver-level authorization, every field is an endpoint, every argument is a parameter

GraphQL is REST with a more powerful query language, which means a more powerful attack surface. Pentest at the schema level, not the URL level.

Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.