GraphQL security testing: one endpoint, every resolver, every caller.
GraphQL lets the client decide what to fetch, how deep to go and how many operations to send at once. That flexibility moves security from the route to the resolver, and it answers almost everything with 200 OK. This guide covers what to test, how to tell a secure response from a leak, and how to keep it tested.
GraphQL Security Test Cases, by Attack Class
GraphQL has no per-endpoint verbs to iterate over, so organize tests by what the attacker is trying to do. Pick a class to see the operation to send and the response a secure API returns.
GraphQL Security Test Run: Why the Status Code Tells You Nothing
Ten operations against one schema, as three identities. Every response is 200. The verdict comes from what's inside: the data returned, the errors raised and how much work the server did.
Illustrative run · synthetic schema and data · 20 s replay
Nested Authorization Example: Walking the Graph Into Another Org
The root project query checks membership. The nested sharedWith and members resolvers don't. Three hops later, alice is reading another organization's people.
Testing REST APIs instead? →Illustrative finding · synthetic data
What a Secure GraphQL Response Looks Like
In GraphQL, assertions target the body. Write each test against one of these shapes, and treat anything else as a finding.
Forbidden field
{ data: { project: null }, errors: [{ extensions:{ code:"FORBIDDEN" } }] }Caller is authenticated but may not read this object or field.
RED FLAG · Data returned, or a partial object with some fields filled.Not authenticated
errors: [{ extensions:{ code:"UNAUTHENTICATED" } }]No token, or an invalid or expired one.
RED FLAG · Anonymous callers receive any non-public data.Validation error
errors: [{ message:"Cannot query field" }]Unknown field, bad argument or input type mismatch.
RED FLAG · "Did you mean …" suggestions in production.Depth or cost rejected
errors: [{ message:"Query too complex" }]Query exceeds the depth, cost or alias limits.
RED FLAG · Slow success: the server ran the whole thing.Rate limited
errors: [{ extensions:{ code:"RATE_LIMITED" } }]Caller exceeds limits counted per operation or per field.
RED FLAG · Hundreds of aliased attempts all executed.Persisted query only
errors: [{ message:"PersistedQueryNotFound" }]Server accepts only pre-registered operations from first-party clients.
RED FLAG · Arbitrary queries accepted from the public client.Introspection off
errors: [{ message:"introspection disabled" }]__schema and __type requested in production.
RED FLAG · Full schema returned to anonymous callers.Generic server error
errors: [{ message:"Internal error" }]Something failed; details logged server-side only.
RED FLAG · Stack traces, SQL or resolver paths in extensions.Error codes vary by server; FORBIDDEN and UNAUTHENTICATED follow common conventions. Use whatever your server documents, consistently.
How to Test a GraphQL API: From Schema to CI
Six steps that cover every type and field, not just the operations your client happens to send.
Choosing an API security testing tool →Get the full schema
Use the SDL from the repo or introspection in staging. Compare it with production to catch debug types and mutations.
Map types to owners
For each type, record who may read it and which fields need extra privileges. Most schemas don't encode this.
Generate paths, not just operations
Build queries that reach each sensitive type through every relationship, since each path is a separate check.
Run as every identity
Two users per role across two orgs, plus anonymous. Compare what each one receives for the same operation.
Assert on body, cost and limits
Expect specific nulls and error codes; time and count work for depth, alias and batching tests.
Run on schema change
Trigger the suite whenever the schema or a resolver changes; new fields and relationships are where leaks appear.
GraphQL Validation That Checks Every Resolver
Hayrok reads your schema, builds operations that reach every type through every path, and runs them as each identity you define. It asserts on data and errors rather than status codes, and records each leak with the operation that caused it.
Schema-aware coverage
Builds operations from your SDL that reach every type through every relationship.
Every identity, every path
Runs each operation as each role and org, and compares what comes back.
Body-level assertions
Judges data, nulls and error codes, not HTTP status.
Cost and batching scenarios
Depth, alias and batch tests run within approved limits on staging.
Evidence per leak
Each finding stores the operation, the identity and the redacted response in Evidence Fabric.
GraphQL Security Testing FAQ
Testing a GraphQL API the way an attacker would: walking relationships into data you shouldn't see, requesting sensitive fields, abusing introspection, sending expensive or batched queries and setting privileged mutation inputs, then checking the data and errors returned.