GraphQL introspection is a built-in feature that lets anyone query your API for its own schema (every type, field, query, mutation, and argument your backend supports) without needing any documentation or credentials. It's essential during development for tools like GraphiQL and Apollo Studio, but if it's still reachable on your production endpoint, anyone can send one request and get a complete, machine-readable map of your entire API surface, including fields and mutations you never intended to advertise.
Why this happens in AI-generated apps
Most GraphQL server libraries (Apollo Server, GraphQL Yoga, and the GraphQL scaffolding several AI app builders generate by default) ship with introspection turned on, because it's what makes the local development experience (autocomplete, the built-in playground, schema-aware tooling) work at all. Turning it off is an explicit production-only configuration step, not a default, so a generated backend that never got a distinct production config keeps introspection live on the exact same endpoint real users hit.
The app itself behaves identically either way from a user's perspective: nothing about the product looks or works differently with introspection on versus off. That's exactly why it tends to ship unnoticed.
What an exposed schema actually hands over
A resolved introspection query returns every object type your API works with, every field on those types (including ones your frontend never queries), every mutation available and its exact argument shape, and any deprecation notices, which often describe what a field used to do or what replaced it. For someone probing your app, this replaces the slow trial-and-error of guessing field and mutation names with a complete, accurate reference handed to them in one response.
This is reconnaissance, not an exploit by itself: introspection alone doesn't read or change data. But it removes the single biggest barrier (not knowing what's there) to finding a real authorization gap on a specific mutation or field faster.
How to fix it
Disable introspection outright in production, or require authentication to access it if internal tooling genuinely needs it there.
- Apollo Server: set `introspection: false` in production (it defaults to disabled in production in recent versions, but confirm rather than assume).
- GraphQL Yoga / graphql-http: pass `introspection: false` (or the equivalent option) when constructing the server for the production environment.
- If a team genuinely needs introspection against production data, put it behind the same authentication your app already uses. Never leave it open to anonymous requests.
- Re-scan after deploying to confirm the introspection query no longer resolves.
Frequently asked
Does disabling introspection break my own frontend?
No. A production frontend is built against a schema that was already generated at build time (via codegen) or is simply hardcoded into the queries it sends: it doesn't need to introspect the live server at runtime. Introspection is a development/tooling convenience, not something a shipped app depends on.
Is introspection itself a vulnerability, or just information disclosure?
By itself it's information disclosure, not a direct exploit: it doesn't read data or execute a mutation. The risk is what it enables: it turns finding a real bug elsewhere in your API (a missing auth check on a specific mutation, an over-broad field) from a guessing game into a lookup.