~/home/study/graphql-schema-introspection

GraphQL __schema Introspection: From Discovery to Defense

Learn how to enumerate GraphQL schemas via the __schema introspection endpoint, automate extraction, uncover hidden types, assess field-level auth, and export schemas for deeper analysis.

Introduction

GraphQL's introspection system, exposed via the special __schema field, allows clients to retrieve the complete type system of an API. Security testers leverage this feature to map out every query, mutation, and type that a service offers, often revealing more than the public documentation.

Understanding and mastering __schema introspection is essential because it provides a low-effort avenue to enumerate attack surface, discover hidden endpoints, and infer authorization logic‑all without authentication in many mis‑configured deployments.

Real‑world incidents, such as the 2023 breach of a fintech GraphQL gateway that leaked internal admin types, demonstrate the impact of unchecked introspection.

Prerequisites

  • Familiarity with basic GraphQL concepts (queries, mutations, types, resolvers).
  • Hands‑on experience with API endpoint enumeration tools (e.g., ffuf, dirsearch).
  • Understanding of Swagger/OpenAPI discovery techniques, as many organizations expose both REST and GraphQL interfaces.
  • Command‑line proficiency (curl, jq) and a modern browser.

Core Concepts

The GraphQL introspection system is defined by the GraphQL Specification. When a client sends a query like { __schema { types { name } } }, the server returns a JSON payload describing every type in the schema.

Key introspection fields:

  • __schema – top‑level entry point.
  • types – array of all object, interface, union, enum, and scalar types.
  • queryType, mutationType, subscriptionType – entry points for operation roots.
  • directives – list of supported directives (e.g., @deprecated, @include).

When introspection is enabled, the server does not differentiate between authenticated and unauthenticated callers unless explicitly coded. Attackers can therefore harvest the entire public contract of the API.

Using curl and GraphQL‑Playground to query the __schema endpoint

Manual querying is a good starting point. Below are two common approaches.

curl

curl -s -X POST -H "Content-Type: application/json" -d '{"query":"{ __schema { types { name kind description } } }"}' GRAPHQL_ENDPOINT | jq '.'

This command sends a POST request with a JSON body containing the introspection query. The jq filter pretty‑prints the JSON response.

GraphQL Playground / GraphiQL

Many services expose an interactive IDE at /playground or /graphiql. Load the page, open the “Docs” pane, and you’ll see the entire schema rendered automatically. If the IDE is secured, you can still manually run the introspection query in the editor:

{ __schema { types { name kind description } }
}

Observe the response in the “Response” tab. This visual approach helps you quickly spot anomalies, such as types that should be internal (e.g., AdminUser) appearing in the public schema.

Automating schema extraction with gqlmap and graphql‑introspection‑tool

Manually copying JSON is tedious for large schemas. Automation tools streamline extraction, formatting, and subsequent analysis.

gqlmap

pip install gqlmap
gqlmap -u GRAPHQL_ENDPOINT -i

The -i flag tells gqlmap to perform an introspection query and dump the result to schema.json. Gqlmap also attempts to enumerate hidden queries by testing for common naming patterns.

graphql‑introspection‑tool (gint)

npm install -g graphql-introspection-tool
gint -e GRAPHQL_ENDPOINT -o schema.graphql

This Node‑based utility fetches the schema and writes it in SDL (Schema Definition Language) format, which is more readable for manual review and can be fed into static analysis tools.

Identifying hidden types, queries, and mutations

Even when introspection is disabled, developers sometimes forget to guard internal fields. Techniques to uncover hidden elements include:

  1. Error‑based probing: Send malformed queries that reference guessed type names. GraphQL often returns an error like “Cannot query field adminSecret on type Query.” The error message can confirm the existence of a field.
  2. Introspection bypass: Some servers expose a secondary endpoint (e.g., /graphql/v2) that still allows __schema queries.
  3. Schema stitching leakage: If the service aggregates multiple micro‑services, introspection may reveal types from downstream APIs that are not intended for external consumption.

Example of an error‑based probe with curl:

curl -s -X POST -H "Content-Type: application/json" -d '{"query":"{ adminSecret }"}' GRAPHQL_ENDPOINT

If the response contains “Cannot query field adminSecret on type Query,” you know the field exists but is not exposed to the current role.

Assessing field‑level authorization based on schema information

Introspection alone does not disclose runtime authorization rules, but the schema can give clues:

  • Fields annotated with the @requires directive (custom) often indicate role checks.
  • Deprecated fields may still be functional for privileged users.
  • Complex input types (e.g., AdminActionInput) can hint at privileged operations.

Combine schema data with brute‑force role testing:

# Example: test a possibly protected mutation
curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $USER_TOKEN" -d '{"query":"mutation { deleteUser(id: \"1\") { success } }"}' GRAPHQL_ENDPOINT | jq '.'

Iterate over discovered mutations while swapping tokens (guest, user, admin) to map which token grants access to which fields.

Exporting the schema to SDL/JSON for further analysis

Once you have the raw introspection JSON, transform it into formats suitable for other tools.

Using graphql‑codegen

npm install -g @graphql-codegen/cli
graphql-codegen init # Choose "Introspection JSON" as source
graphql-codegen --config codegen.yml

The generated schema.graphql file can be fed into static analysis frameworks like semgrep or bandit (via custom rules) to search for insecure patterns.

Converting JSON to SDL with Apollo tools

npm install -g apollo
apollo client:download-schema --endpoint=GRAPHQL_ENDPOINT schema.json
apollo client:codegen --target=typescript --outputFlat schema.ts schema.json

The schema.ts file contains TypeScript definitions that can be used to type‑check client code or to generate fuzzing payloads automatically.

Practical Examples

Below is a complete workflow that a penetration tester might follow against a vulnerable GraphQL service.

  1. Discover the endpoint using directory brute‑forcing (ffuf):
    ffuf -u TARGET_URL -w wordlist.txt -mc 200
  2. Verify introspection is enabled:
    curl -s -X POST -H "Content-Type: application/json" -d '{"query":"{ __schema { queryType { name } } }"}' GRAPHQL_ENDPOINT | jq '.'
  3. Dump the full schema with gqlmap:
    gqlmap -u GRAPHQL_ENDPOINT -i -o full_schema.json
  4. Convert to SDL for manual review:
    graphql-introspection-tool -e GRAPHQL_ENDPOINT -o schema.graphql
  5. Search for suspicious mutations:
    grep -i "delete\|drop\|admin" schema.graphql
  6. Attempt to invoke a discovered mutation with a low‑privilege token:
    curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $LOW_TOKEN" -d '{"query":"mutation { deleteUser(id: \"5\") { success } }"}' GRAPHQL_ENDPOINT | jq '.'

The output will indicate whether the mutation is protected, mis‑configured, or outright exploitable.

Tools & Commands

  • curl – raw HTTP client for manual queries.
  • jq – JSON pretty‑printer and filter.
  • gqlmap – Python‑based schema dumper and enumeration helper.
  • graphql‑introspection‑tool (gint) – Node utility for SDL export.
  • Apollo CLI – Official GraphQL tooling for schema download and codegen.
  • ffuf / dirsearch – Endpoint discovery before introspection.
  • GraphQL Playground / GraphiQL – Interactive IDE for visual exploration.

Defense & Mitigation

Disabling introspection in production is the primary mitigation, but it must be done carefully to avoid breaking legitimate tooling.

  • Set introspection: false in server configuration (e.g., Apollo Server, GraphQL‑Java).
  • Apply field‑level authorization middleware that validates the caller before returning any type information.
  • Rate‑limit the POST /graphql endpoint to prevent automated schema harvesting.
  • Implement a “schema version” endpoint that returns a sanitized, public‑facing version of the schema, while keeping internal types hidden.
  • Audit custom directives; ensure they do not inadvertently expose security‑relevant metadata.

Common Mistakes

  • Assuming introspection is always disabled in production. Many teams forget to toggle the flag after development.
  • Relying solely on the public schema for security reviews. Hidden fields can be accessed via error‑based probing.
  • Neglecting to test with multiple authentication tokens. Some fields are gated per role, not per endpoint.
  • Exporting the schema but ignoring directives. Custom directives often encode access control logic.

Real‑World Impact

In 2022, a major SaaS provider exposed its internal admin GraphQL schema, allowing attackers to enumerate resetUserPassword and escalatePrivileges mutations. The breach led to credential theft for over 10,000 accounts. Post‑mortem analysis showed that the production Apollo Server had introspection: true and that the developers relied on “security through obscurity.”

My experience consulting for fintech firms shows that once the schema is obtained, creating a targeted fuzzing campaign (e.g., with graphql-fuzz) can uncover injection vectors, overly permissive resolvers, and logic bugs within minutes.

Trend‑wise, as more organizations adopt GraphQL for internal APIs, the attack surface expands. Automated CI pipelines now include schema‑exposure checks to prevent accidental leaks.

Practice Exercises

  1. Use ffuf to locate a hidden GraphQL endpoint on a test server (e.g., GRAPHQL_ENDPOINT).
  2. Perform an introspection query with curl and save the JSON output.
  3. Convert the JSON to SDL using graphql-introspection-tool and identify any types that contain the word “Admin”.
  4. Write a small Python script that iterates over all mutations in the SDL and attempts to invoke each with a dummy token, logging success or failure.
  5. Configure Apollo Server to disable introspection and verify that the same queries now return an error.

Further Reading

  • Official GraphQL Specification – Introspection Section.
  • OWASP GraphQL Security Cheat Sheet.
  • “GraphQL Security: The Good, the Bad, and the Ugly” – Black Hat 2023 presentation.
  • Tools: graphql-fuzz, gqlgen security guide, Semgrep GraphQL rules.
  • Related topics: “Authorization in GraphQL”, “GraphQL Batching Attacks”, “Schema Stitching Risks”.

Summary

Introspection via the __schema field is a double‑edged sword: it empowers developers and clients, yet it can expose the full attack surface when left unchecked. By mastering manual queries, automation tools, hidden‑type detection, and schema export techniques, security professionals can both assess risk and advise on robust mitigations.

Key takeaways:

  • Always verify whether introspection is enabled on production endpoints.
  • Automate extraction with gqlmap or gint for repeatable assessments.
  • Correlate schema data with role‑based testing to map field‑level authorizations.
  • Export schemas to SDL/JSON for static analysis and fuzzing pipelines.
  • Implement defense‑in‑depth: disable introspection, enforce middleware checks, and monitor for abnormal query patterns.