GraphQL Schema Security Auditor Guide: Find the Weak Points in Your API

A GraphQL API is defined by its schema: the types, fields, queries, and mutations it offers. That schema is also its attack surface. Unlike a traditional API with fixed endpoints, a GraphQL API lets the client choose exactly which fields to request, and to nest those requests as deeply as it likes. That flexibility is the point of GraphQL, and it is also the risk. A field that returns a user's private details, a query that walks from a user to their orders to every order item without limit, or a mutation that lets anyone change someone else's data can all be hiding in plain sight in the schema, waiting for a curious client. The GraphQL Schema Security Auditor checks schema text you paste for these patterns, flagging risky fields, sensitive-sounding names, and structures that invite abuse, so you can fix them before the API goes public.

The auditor works on text, and that boundary matters. You paste a schema, or a representative extract of one, and it reads the structure: which types exist, which fields return sensitive-sounding data, where lists can grow without bound, and where nested types allow deep queries. It does not connect to your live server, does not test your authentication, and does not prove an API is safe. A schema that passes this check can still be insecure if its resolvers fail to check permissions, and a schema that raises flags may be perfectly safe if its resolvers enforce strict rules. Treat the audit as a review checklist generated from the contract, not as a security certificate. Real assurance comes from combining it with authentication tests, authorisation tests on live resolvers, and a review by someone who understands the data.

The patterns that matter most

The first pattern is sensitive data exposure: fields named like password, token, secret, email, phone, address, or internal identifiers that have no business being in a client-facing schema. Even if a resolver returns null for other users today, the field's presence invites attempts and leaks information about your data model. The second is unbounded lists: a field returning a list with no pagination arguments, no first or last limit, invites a client to request everything at once. The third is deep nesting: types that reference each other in cycles, such as user to posts to author back to user, allow queries that expand exponentially and exhaust a server. The fourth is dangerous mutations: operations that delete, transfer, or change ownership without obvious safeguards in the schema, such as missing confirmation arguments. The fifth is introspection: a production API that answers schema queries from anyone hands an attacker the complete map of the API for free. None of these patterns is automatically a vulnerability, but each one deserves a written reason for being there.

Worked example

Consider a sample schema extract, with values clearly labelled as an illustration. It defines a User type with 12 fields, of which 3 are sensitive-sounding: email, phone, and internalNotes, which is 25 percent of the fields, since 3 divided by 12 is 0.25. It defines a posts field returning a list with no pagination, and a Post type whose author field returns a User, creating a cycle. A client could therefore write a query nesting user to posts to author to posts repeatedly. Suppose each level expands to 10 items: one level gives 10 items, two levels give 10 times 10, which is 100, three levels give 1,000, and five levels give 100,000 items from a single request, since 10 to the power of 5 is 100,000. That is the arithmetic of a nesting attack, and it shows why depth limits matter more than any single field. The fixes are concrete: remove internalNotes from the client schema entirely, paginate posts with a maximum page size of, say, 50, cap query depth at a number your resolvers can handle, and disable introspection in production. After those fixes, the same audit should show zero sensitive fields exposed, one paginated list, and a documented depth limit, and the five-level expansion becomes impossible by construction rather than by hope.

Mistakes to avoid

The first mistake is pasting a real production schema, complete with internal types and comments, into any online checker. Paste a cleaned extract, or a schema from a staging environment, with secrets, tokens, and internal details removed first. The second is fixing only the flagged fields while leaving resolver authorisation untested: a schema can look clean while a resolver still returns another user's data to anyone who asks. The third is adding pagination without a maximum, which still allows a client to request a million items in one page. The fourth is disabling introspection but forgetting that the schema may still be published in documentation, client code, or error messages. The fifth is treating the auditor's silence as approval: it checks patterns in text, not behaviour, and some of the worst API flaws, such as broken object-level authorisation, are invisible in a schema. Use the audit to start the review, not to end it.

Putting it into practice

Run the audit on every schema change that adds a field, a type, or a mutation, and make the flagged list part of code review: each flag either gets fixed or gets a written justification from the API owner. Keep a small set of rules for your team: no sensitive fields in client schemas, every list paginated with a maximum, a documented query depth and complexity limit, introspection off in production, and mutations that change ownership requiring explicit confirmation. Test resolvers separately with authenticated requests as different users, confirming that each user sees only their own data. For related checks, the JWT Security Analyzer helps review the tokens your API uses for authentication, and the JSON Studio helps inspect structured payloads cleanly. The companion guide on CSP Checker covers a different layer of web defence, a reminder that API security is one layer among several, and no single check covers them all.

Key points

  • A GraphQL schema is the contract of an API, and anything it exposes can be queried
  • Introspection, deep nesting, and missing limits are the classic abuse routes
  • An auditor checks schema text you paste, it does not probe a live server or prove safety
  • Never paste production secrets, tokens, or private schema details into a checker

In short: read your schema as an attacker would, because that is how it will be read. Remove sensitive fields, paginate every list with a maximum, limit depth, switch introspection off in production, and test your resolvers as different users. The audit finds the patterns; your fixes and tests provide the safety.