Stop 32 of 42 · The Blueprints · GraphQL exposure

The service desk with everything on the menu

The bank has a flexible service desk: customers ask for exactly what they want. Mallory discovers three things. The desk will print a menu of everything it can do. It counts a stack of requests as one. And it will happily follow requests nested inside requests.

Severity Low–MediumCategory Info Disclosure / API ExposureThe BlueprintsSources checked 25 Oct 2026

Watch it happen

Play it as

Mallory asks the service desk what it can do, then hands in a slip with a thousand requests, then a request nested many levels deep. The desk obeys and strains.

Arrival

The bank’s flexible service desk lets customers ask for exactly what they want. Alice walks up to it, and Mallory comes in behind her.

1 / 5

In bank terms and app terms

In the bankIn your app
Menu of everythingIntrospection: __schema returns every type, query and mutation
A stack of requests in one slipBatching and aliases: many queries in one HTTP request, which get around per-request rate limits
Requests nested inside requestsDeeply nested queries that multiply database work (denial of service)
Sign on the deskDepth and batch limits, query cost limits, introspection off in production

Are you exposed?

You might be exposed if…
  • A /graphql endpoint answers { __schema { types { name } } } in production.
  • You rate-limit by HTTP request count, but one request can contain many queries.
  • There is no limit on query depth or cost, and resolvers do not check permissions themselves.
What to do about it
  1. Turn introspection off in production (Apollo has an option, Yoga a plugin) and disable “did you mean” field suggestions. This hides the map, it is not a lock.
  2. Cap query depth, complexity and alias count, and limit or disable batching.
  3. Check permissions inside every resolver, since hiding a field in the schema is not access control. Rate limit by query cost.

Track these in your to-do list →

What it looks like in code

// GOOD: Disable introspection in production
const yoga = createYoga({
  schema,
  graphiql: false,  // Disable playground
  maskedErrors: true,
  plugins: [
    useDisableIntrospection(),  // Block __schema queries
    useDepthLimit({ maxDepth: 10 }),
    useRateLimiter({ identifyFn: (ctx) => ctx.request.headers.get("x-forwarded-for") ?? "anon" }) // plus @rateLimit directives on expensive fields
  ]
})

Ask your AI tool to fix it

Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.

Prompt
Harden our GraphQL server. Disable introspection and any playground in production, add query depth, complexity and alias limits, limit or disable array batching, add rate limiting that counts queries rather than HTTP requests, and make sure every resolver enforces authorization. Show the configuration changes.

Where this comes from

The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.

  • Securing Your GraphQL APIGraphQL FoundationDepth, alias and batch limits, rate limiting; field suggestions leak schema details
  • GraphQL Cheat SheetOWASPDisable introspection and GraphiQL in production; query depth limits; per-resolver access control
  • GraphQL API vulnerabilitiesPortSwigger Web Security AcademyIntrospection reveals the schema; 'Did you mean' hints; aliases bypass rate limiting
  • IntrospectionGraphQL FoundationThe __schema field is always available and lists every type
  • AuthorizationGraphQL FoundationEnforce permissions in the business logic layer, checked in resolvers, not the schema
  • GraphQL Yoga: IntrospectionThe GuildYoga can disable introspection and field suggestions

Spot a mistake or something out of date? Report a correction · How these guides are made and checked

Go deeper in isitsecure

The free, open-source scanner checks for most of the problems in these guides.