Skip to content

GraphQL Security Testing: Introspection, Batching and Authorization Flaws

GraphQL security testing explained: finding endpoints, introspection and suggestions, IDOR, batching and alias abuse, DoS, CSRF, and how to test each.

Invadel Team9 min read

GraphQL does not remove an API’s attack surface, it rearranges it. One endpoint replaces dozens, the client asks for exactly the fields it wants, and the schema often describes the whole graph to anyone who queries it. GraphQL security testing is the discipline of finding where that flexibility turns into an authorization gap, a denial-of-service lever, or a data leak. This guide covers the vulnerability classes specific to GraphQL, how each is tested, and how to defend it. For the buyer-facing service, see our API penetration testing, and for the full method across REST, GraphQL and SOAP, the API penetration testing checklist.

Why GraphQL security testing needs its own angle

A REST API spreads its surface across many endpoints and HTTP verbs. GraphQL collapses that into a single endpoint that accepts a query language, so the interesting questions change. Instead of “which endpoints exist,” it is “what does the schema expose.” Instead of “is this endpoint authorized,” it is “is every field and every resolver authorized.” And instead of “is this endpoint rate-limited,” it is “can one request carry a hundred operations.” The OWASP Web Security Testing Guide treats GraphQL as its own testing topic for exactly this reason, and the OWASP API Security Top 10 categories, especially broken object-level authorization, still apply underneath.

Finding the endpoint and fingerprinting the server

GraphQL usually lives at a predictable path: /graphql, /api, /api/graphql, /graphql/api or /graphql/graphql. A single universal query confirms it. As PortSwigger notes, “if you send query{__typename} to any GraphQL endpoint, it will include the string {"data": {"__typename": "query"}} somewhere in its response” (PortSwigger, GraphQL API vulnerabilities). After locating it, testers fingerprint the server engine (Apollo, graphql-ruby, Hasura and others) with a tool such as graphw00f, because the engine determines which defenses and which default behaviors are in play, including whether the server helpfully suggests field names.

Introspection and schema recovery

Introspection lets a client ask the server for its entire schema: every type, query, mutation and field. It is a development convenience and, left on in production, a gift to an attacker. The OWASP GraphQL Cheat Sheet notes that introspection, often enabled by default and without authentication, “allows the consumer of your API to learn everything about your API,” and tells you to disable introspection queries “system-wide in any production or publicly accessible environments” (OWASP GraphQL Cheat Sheet).

Disabling introspection is not the whole fix. Many servers still return “did you mean” field suggestions on a mistyped query, and tools such as Clairvoyance walk those suggestions to reconstruct the schema without introspection at all. In Apollo Server, introspection defaults to true “unless the NODE_ENV environment variable is set to production,” and a separate option, hideSchemaDetailsFromClientErrors, “strips out ‘did you mean’ suggestions when an operation fails validation” and defaults to false, although Apollo recommends turning it on in production (Apollo Server documentation). A test checks both: is introspection off, and are suggestions off. Turning off one and leaving the other is a common half-fix.

Authorization: the flaw that matters most

GraphQL moves authorization to the field and resolver, and that is where it most often breaks. The schema tempts developers into thinking that if a field exists, anyone who can reach the endpoint can read it. The cheat sheet’s rule is the opposite: “Always validate that the requester is authorized to view or mutate/modify the data they are requesting.”

Testing covers two layers:

  • Object-level authorization (IDOR / BOLA). As PortSwigger puts it, a user “could potentially access information they should not have simply by supplying an argument that corresponds to that information.” The test replays a query as a low-privilege user, then as a second user of the same role, changing IDs to reach records that should be out of bounds.
  • Field-level authorization. A low-privilege token may be blocked from a users query but still able to select a sensitive field on a nested object it can otherwise reach. The test walks nested queries selecting fields a role should never see, and probes mutations that change data the role should not be able to change.

This is the single highest-value area of a GraphQL test, and scanners rarely find it, because only a person who understands what the application is for knows which record belongs to whom.

Batching and alias abuse

GraphQL lets a client send many operations in one HTTP request, either as an array of queries (batching) or by using aliases to repeat the same field many times in one query. Attackers use this to defeat rate limits that count HTTP requests rather than operations. The cheat sheet warns these attacks “will likely bypass existing rate limits in tools like Nginx” because they arrive as a single request. The classic case is brute-forcing a login or a one-time code: a hundred aliased login attempts in one request slip past a per-request limiter. A test attempts aliased and batched operations against sensitive mutations to see whether the limits count operations or just requests.

Denial of service through query complexity

Because a client controls the shape of the query, it controls the work the server does. Deeply nested queries following circular relationships, and wide queries selecting many fields, can force expensive resolution. The cheat sheet notes that query depth and amount limiting “by default … can both be unlimited which may lead to a DoS,” and recommends depth limits, amount limits, pagination, query cost analysis and timeouts. A test measures how deep and how wide a query the server will accept before it slows or fails, and whether cost analysis or timeouts are in place. Introspection queries themselves can be nested to abusive depth, which is another reason to restrict them.

Injection through resolvers

A resolver is code, and it often passes arguments into a database query, an OS command or a downstream service. GraphQL does not sanitize inputs for you. The cheat sheet’s guidance is to validate all incoming data with allow-lists, use specific scalar and enum types, and use parameterized statements. A test sends injection payloads through query arguments and variables looking for SQL, NoSQL, command and server-side template injection reached through the resolver layer, exactly as it would through any other input. These are the same injection classes the OWASP Top 10 groups for web applications; GraphQL only changes how the payload arrives.

CSRF and request-method handling

If a GraphQL endpoint accepts requests it should not, it opens cross-site request forgery. PortSwigger notes that endpoints accepting GET requests or x-www-form-urlencoded POST bodies face CSRF risk, because “alternative methods … can be sent by a browser,” while a JSON-only POST is much harder to forge cross-site. A test checks which content types and methods the endpoint accepts and whether state-changing mutations are reachable over a forgeable request.

The GraphQL test at a glance

Vulnerability class What the test does Core defense
Endpoint discovery and fingerprinting query{__typename}, common paths, graphw00f Do not rely on obscurity
Introspection and suggestions Pull the schema; recover it via suggestions if introspection is off Disable introspection and field suggestions in production
Object-level authorization (IDOR) Replay queries across users and IDs Enforce authorization in every resolver
Field-level authorization Select sensitive fields on nested objects as a low-privilege role Field-level access control
Batching and alias abuse Aliased and batched operations against sensitive mutations Rate-limit by operation, not request
Query complexity DoS Deeply nested and wide queries Depth, cost, and timeout limits; pagination
Injection Payloads through arguments and variables Input validation, parameterized queries
CSRF Test accepted methods and content types Accept only JSON-encoded POST

Tools testers use

Manual testing does the authorization work, but a few tools speed the rest: InQL, a Burp Suite extension from Doyensec for generating queries, detecting circular references and brute-forcing the schema when introspection is disabled; graphw00f for engine fingerprinting; Clairvoyance for suggestion-based schema recovery; GraphQL Voyager for visualizing a recovered schema; and Burp Suite’s own GraphQL support. Tools map the schema and the attack surface; a person decides which of the exposed fields and objects should not be reachable by the role in front of them, and that judgment is the test.

How this fits an API engagement

GraphQL rarely stands alone. It usually sits in front of the same data a REST or internal API also serves, so a GraphQL test is part of a wider API penetration test, which covers the OWASP API Security Top 10 across REST, GraphQL and SOAP from $4,000. If the GraphQL API is the back end of a single-page application, a web application penetration test tests both together, since the front end is a thin layer over the graph. Our API security best practices guide covers the defensive side for developers. API-first SaaS and fintech teams, the usual GraphQL adopters, will find the sector context in our pages for SaaS and fintech.

Frequently asked questions

What is GraphQL security testing? Testing a GraphQL API for the vulnerabilities its design invites: exposed schema through introspection, missing authorization at the field and object level, rate-limit bypass through batching and aliases, denial of service through query complexity, injection through resolvers, and CSRF. It is part of API penetration testing.

Is disabling introspection enough to secure a GraphQL API? No. It hides the schema, but field suggestions can still leak it, and it does nothing for authorization, batching or injection. Disable introspection and suggestions in production, then test the authorization and rate-limiting that actually protect the data.

What is the most common serious GraphQL vulnerability? Broken authorization at the object or field level. Because any field the schema exposes looks reachable, developers often check access at the endpoint but not on each resolver, letting a low-privilege user read or change data they should not.

How do attackers bypass GraphQL rate limits? By batching many operations into one HTTP request or using aliases to repeat a field many times in one query. Limits that count requests see one request; the fix is to limit by operation.

Do you test GraphQL as part of an API penetration test? Yes. GraphQL testing is included in our API penetration test, which covers REST, GraphQL and SOAP against the OWASP API Security Top 10, with the authorization and batching checks GraphQL specifically needs.

The short version

GraphQL security testing follows the surface GraphQL creates: find and fingerprint the endpoint, check whether the schema leaks through introspection or suggestions, then spend the time where it matters, on object-level and field-level authorization, batching and alias abuse, query-complexity denial of service, injection through resolvers, and CSRF. Tools recover the schema; people decide what should not be reachable. To have your GraphQL API tested as part of a fixed-price API engagement with a free retest, scope a test.

Written by

Invadel Team

Senior penetration testers writing from real engagements, the same team that scopes, tests, and reports for our clients. About Invadel →

All articlesApplication Pentesting

Find out what an attacker sees.

Tell us what to test and see your fixed price.

Prefer the full scoping questionnaire? 
Start the conversation