GraphQL Hacking: The Complete Practical Guide
GraphQL Introspection and Schema Discovery
How to dump a GraphQL schema with introspection: the __schema and __type queries, reading the result, and prioritizing the dangerous mutations to attack.
Published
When introspection is enabled, a single query returns the entire schema, which is a complete map of the attack surface including operations no screen ever calls. This page covers running introspection, reading the result, and turning it into a target list. Practice on a free live target.
What introspection is
GraphQL can describe itself. The meta-fields __schema and __type let a client ask the server for its own types, fields, arguments, and operations. It exists so tools can autocomplete and document an API, but it volunteers the whole structure to anyone who asks, which is why it should be off in production.
Step 1: run the introspection query
A compact introspection query that lists types, their fields, and the mutation names:
POST /graphql HTTP/1.1
Host: target.example
Content-Type: application/json
{"query":"{ __schema { queryType { name } mutationType { fields { name args { name type { name kind } } } } types { name kind } } }"}HTTP/1.1 200 OK
Content-Type: application/json
{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":{"fields":[{"name":"login","args":[{"name":"user","type":{"name":"String","kind":"SCALAR"}},{"name":"pass","type":{"name":"String","kind":"SCALAR"}}]},{"name":"setUserRole","args":[{"name":"userId","type":{"name":"ID","kind":"SCALAR"}},{"name":"role","type":{"name":"String","kind":"SCALAR"}}]}]},"types":[{"name":"User","kind":"OBJECT"},{"name":"Query","kind":"OBJECT"}]}}}The types array here is trimmed to the two that matter. A real response also lists the built-in introspection types (__Schema, __Type) and scalars (String, Int, and so on), so expect fifteen or more entries. The full introspection query (the one GraphiQL uses) is longer and resolves nested ofType wrappers for lists and non-nulls. The cheat sheet has a fuller version. This compact form is enough to see the operations and their arguments.
Step 2: read and map the schema
Turn the JSON into a target map. The useful structure is:
- Query fields: what you can read, and which take an
idorfilterargument. - Mutation fields: what you can change, and the arguments each needs.
- Input types: object-shaped arguments (wrapped values), which matter for injection.
A visualizer helps on a large schema:
GraphQL Voyager renders the type graph visually
SDL reconstruction many clients turn introspection JSON back into readable schema text
__type(name:"User") pull one type in detail when the full dump is noisyStep 3: prioritize the dangerous operations
Not every operation is worth your time. Rank them:
setUserRole / updateUser role and account changes -> authorization testing
createApiKey / refund secrets and money -> authorization + abuse
login / resetPassword auth -> batching brute force, injection
product(category:) / user(id:) args that hit a DB -> injection, BOLA
User.passwordResetToken a field the UI never shows -> request it directlyIntrospection just told you these exist. That is the whole value: the UI would never have shown you setUserRole or a passwordResetToken field.
Edge variants
{ __type(name: "User") { name fields { name type { name kind } } } }
{ __schema { types { name } } }
{ __schema { mutationType { fields { name } } } }The single-type probe (__type) is the surgical tool when the full dump is too large to read. If __schema is blocked, the schema is still recoverable: see bypassing introspection defenses.
Fixing it
- Disable introspection in production. It is the single biggest reduction in GraphQL attack surface.
- Disable field suggestions too, or disabling introspection alone still leaks the schema by fuzzing.
- Authorize sensitive fields and mutations regardless of whether their existence is discoverable.
Full guidance is in preventing GraphQL attacks. Next, recover the schema when introspection is off in bypassing introspection defenses, or dump a schema on a free lab.