← All checks
SecurityTypical severity: Medium

GraphQL Introspection Scanner

Checks whether your GraphQL endpoint exposes its full API schema via enabled introspection.

What it checks

This scanner checks whether your GraphQL endpoint has introspection enabled, which exposes your API's full schema. It detects when anyone can query the entire structure of available types, fields and operations.

Why it matters

With introspection enabled, an attacker gets a detailed map of your API effortlessly, including internal fields and operations you may not have wanted to reveal. That knowledge makes it much easier for them to find weak points and data to explore.

How to fix it

Disable GraphQL introspection in your production environment, keeping it on only for development. Most GraphQL libraries let you do this with a configuration option based on the environment.

How this check works

Scanaris sends a POST request with the smallest possible introspection query, {__schema{queryType{name}}}, to three paths where a GraphQL endpoint usually lives: /graphql, /api/graphql and /v1/graphql. If any of them responds 200 and the body contains __schema or queryType, introspection is enabled and it opens a medium-severity finding with the path. If there is no GraphQL on your site, no path responds that way and there is no finding. The query is read-only, touches no data, and goes through the same time and size limits as the rest of the scan.

Why it matters

Introspection is the GraphQL feature that lets you ask the API about its own schema: every type, every field of every type, every available query and mutation, with their arguments. In development it is essential: it is what the playground, editor autocompletion and code generators rely on. In production, open to anyone, it is a complete map of your backend. An attacker sees that a deleteUser(id) mutation or an internalNotes field exists without having to guess, and goes straight to testing whether the authorisation on each one is done properly. That is why it is medium severity: it exposes no data by itself, but it makes any other permission flaw trivial to find.

How to disable it in production

  • Apollo Server: introspection: "production" !== 'production' when creating the server. Since Apollo 4 it is already off when NODE_ENV is production; if you see it enabled, check that the variable actually reaches your deployment. Also disable the landing page or playground in production.
  • GraphQL Yoga and Envelop: the useDisableIntrospection() plugin from @envelop/disable-introspection, conditioned on the environment.
  • Hasura (the /v1/graphql path): the project's security settings include a per-role introspection control (Cloud and Enterprise). Also make sure the public role has minimal permissions and that the admin secret never travels to the browser.
  • graphql-ruby: disable_introspection_entry_points in the schema class.
  • Python (Graphene, Strawberry, Ariadne): add the NoSchemaIntrospectionCustomRule rule from graphql-core to the validation rules in production.
  • .NET (Hot Chocolate): .AllowIntrospection(false), or the option to toggle introspection per request based on a header or a role.

Disabling introspection is no substitute for authorisation: every query and mutation must check who is asking. Pair it with query depth and complexity limits (they prevent nested queries that take the server down) and, if your server offers it, also turn off field suggestions ("Did you mean…"), which leak names even with introspection closed.

Check it is fixed

curl -s -X POST https://yourdomain.com/graphql -H "Content-Type: application/json" -d '{"query":"{__schema{queryType{name}}}"}'

Repeat with /api/graphql and /v1/graphql. Expected: an error such as "introspection is not allowed", a 400 or 403, or a 404 if there is no GraphQL there. If you see "queryType":{"name":"Query"}, it is still open.

Frequently asked questions

My API is public and documented. Does this affect me?

If you publish the schema on purpose, open introspection reveals nothing new and you can mark the finding as accepted. Most application APIs are not in that situation: they have internal mutations nobody should know about.

My endpoint is on another path. Is it not checked?

Only the three most common paths are probed. If yours lives elsewhere, run the test above against your real path. Other panels and development endpoints that should not respond in production are looked for by exposed endpoints.

What if the endpoint requires authentication?

Then introspection responds 401 and is not flagged. That is the right situation: an attacker without a session gets no schema. Make sure the API's CORS header is not open to any origin; that is what permissive CORS looks at.

Check it on your site

Scan your site free and see if this and 44 other checks pass, with a fix prompt for every issue.

Scan my site free

Related checks