This article describes a GraphQL security lab that teaches how introspection queries can expose hidden admin functionality in APIs. The core problem is that GraphQL servers often leave introspection enabled in production, revealing the complete API schema including undocumented and admin-only fields that lack authorization checks. This matters because attackers can use introspection as a reconnaissance tool to discover and exploit sensitive operations that were never meant to be publicly accessible.
- Introspection reveals complete API surfaceGraphQL's built-in introspection feature allows clients to query a server for its complete schema—all types, queries, mutations, and fields. When enabled in production, this exposes every endpoint including undocumented or admin-only ones that were never linked in the user interface. The server answers introspection queries before any business logic runs, meaning the entire schema is revealed regardless of who is asking.
- Security through obscurity fails completelyThe lab demonstrates that admin queries protected only by not being linked in the UI are trivially discoverable via introspection. Once exposed, if the field lacks an authorization check, calling it requires only knowing its arguments and return fields—both of which introspection provides. This illustrates the principle that obscurity is not access control.
- Attack requires only standard introspection queriesAn attacker sends the standard __schema introspection query to the endpoint, scans the returned fields for administrative or undocumented operations, determines the expected arguments and return fields from the schema map, then calls the hidden query directly to read sensitive data. The entire attack is straightforward enumeration followed by direct invocation.
- Introspection is enabled by default in many frameworksThe article notes that introspection left enabled in production is one of the most common GraphQL findings because many frameworks enable it by default. When combined with missing field-level authorization, this configuration regularly exposes admin operations and sensitive data in real-world bug-bounty reports.
- Real-world classification under OWASP Top 10The article categorizes this vulnerability under OWASP A05 (Security Misconfiguration) when introspection is enabled, and under A01 (Broken Access Control) when sensitive fields lack authorization checks. This dual classification reflects both the configuration error and the underlying authorization failure.
- Defense requires multiple complementary controlsThe article recommends disabling or restricting introspection to authenticated internal use in production, implementing authorization checks on every field and mutation rather than relying on fields being undocumented, applying query depth and cost limits to prevent abuse, and reviewing the schema for fields that should not be reachable by ordinary users. No single control is sufficient—disabling introspection alone does not fix fields that can still be guessed.
- Introspection queries are reconnaissance starting pointThe article advises that on authorized GraphQL testing engagements, running an introspection query first should be the standard approach because the schema serves as a complete map of the API. Hidden mutations and admin queries discovered this way represent the fastest route to high-impact security findings.
Bottom line: Introspection in GraphQL production environments is a critical reconnaissance vulnerability because it exposes the complete API schema including hidden admin operations. Defense requires both disabling introspection in production and implementing proper authorization checks on every sensitive field—neither control alone is sufficient.
📋 In this walkthrough
What this lab teaches
GraphQL servers can describe their own schema through introspection. That is useful in development, but left on in production it hands an attacker a complete map of the API — every query, mutation and field, including undocumented or admin-only ones that were never meant to be discovered.
The lesson: 'not linked anywhere' is not access control. If a field exists in the schema, introspection reveals it, and if it has no authorisation check, anyone can call it.
How GraphqlAPI exposes its schema
GraphqlAPI answers a standard introspection query by listing all of its types and fields. One of those fields is an admin query that returns a secret and was never exposed in the UI — but it is right there in the schema for anyone who asks.
The attack approach
- Send the standard introspection query to the /graphql endpoint to list the schema.
- Read through the available query fields and spot one that looks administrative or undocumented.
- Work out the arguments and return fields it expects from the schema map.
- Call that query directly and read the secret it returns.
Full walkthrough (spoiler)
If the schema came back but you are not sure which field to call, open the steps.
Show the step-by-step solution
- Send an introspection query (the
__schemaquery that lists types and fields) to the endpoint. - Scan the returned query fields for one that is not used anywhere in the visible app — the hidden admin query.
- Build a normal GraphQL query that calls that field, using the return fields introspection showed you.
- Run it. The hidden query returns the admin secret, and the lab marks you solved.
Why it works
Introspection is answered before any business logic runs, so it reveals the whole schema regardless of who is asking. The hidden query is 'protected' only by not being linked in the UI — security through obscurity. Once introspection exposes it and there is no per-field authorisation, calling it is trivial.
Where this happens in the real world
Introspection left enabled in production is one of the most common GraphQL findings, because many frameworks enable it by default. Combined with missing field-level authorisation it regularly exposes admin operations and data in bug-bounty reports. It falls under Security Misconfiguration (A05) and, where the fields lack checks, Broken Access Control (A01) in the OWASP Top 10 (2021).
How to defend against it
- Disable introspection in production, or restrict it to authenticated internal use.
- Authorise every field and mutation — never rely on a field being undocumented.
- Apply query depth and cost limits so the endpoint cannot be abused for heavy or nested queries.
- Review the schema for fields that should not be reachable by ordinary users.
Try it, then go further
Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.
