skip to content

questions

4

What security controls does the GraphQL specification itself define for a server?

level: juniorimportance: must knowfreq 55%

answer

  1. Ask what the document is actually about
  2. Language and evaluation, not callers
  3. Structural rules bound legality, not cost
  4. Transport lives in a separate draft
  5. The gift is the analysable typed document

basics

~20 s

The GraphQL specification defines no security controls at all - only a type system, document syntax, validation rules, an execution algorithm and a response shape. Authentication, authorization, rate limiting, depth caps and cost limits are server policy.

solid answer

~50 s

None. The specification covers the language, the type system, introspection, a list of validation rules, the execution algorithm and the `data`/`errors`/`extensions` response shape - and stops there. It says nothing about who the caller is, whether they may see a field, how big a document may be, or how much work one request may cause. The rules that look protective are structural, not budgetary: fragment spreads must not form cycles, selected fields must exist on the type, leaf fields must not carry a selection set. Those keep a document finite and well-formed; they do not keep it cheap. Even the transport is out of scope - HTTP methods, media types and statuses live in the separate GraphQL over HTTP working draft. So "we are spec-compliant" tells an interviewer nothing about what your endpoint rejects; every limit you have is something your server chose to add.

code

graphql · 23 lines
graphql
query DeepButLegal {
  venue(id: "v-7813") {
    events {
      tiers {
        seats {
          holds {
            order {
              buyer {
                orders {
                  event {
                    venue {
                      name
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

go deeper

for a junior

Be ready to say plainly that the specification defines no authentication, authorization or limits, and to name what it does define: language, type system, introspection, validation, execution, response shape.

for a middle

Explain why the structural validation rules - fragment cycles, field existence, leaf selections - bound a document's legality but not its cost, and where the HTTP contract actually comes from.

for a senior

Show that the specification's silence is the design constraint you work under: every limit is yours, and its position in the pipeline decides what information it has.

for a principal

Own the consequence for a platform: conformance guarantees nothing about abuse resistance, so the organisation needs a documented, owned control set rather than an assumption inherited from the spec.

### What the specification actually contains The GraphQL specification is a document about *language and evaluation*. Its sections describe: the syntax of a GraphQL document (operations, selection sets, fragments, arguments, variables, directives); the type system (object, interface, union, enum, input object, scalar, plus the non-null and list wrappers); introspection (the `__schema`, `__type` and `__typename` meta-fields); a numbered list of validation rules a document must satisfy against a schema; the execution algorithm (how fields are collected, how resolvers are invoked, how values are completed, how errors propagate); and the response format, with its `data`, `errors` and `extensions` keys. Read that list again and notice what is missing. There is no notion of a caller. No credentials, no roles, no sessions. No budget of any kind - no maximum depth, no maximum number of fields, no cost model, no request quota, no timeout. No rules about how large a request body may be, how many operations may arrive together, or how long a subscription may stay open. A server that accepts a two-thousand-level-deep document and spends forty seconds resolving it is fully conformant. ### The rules that look like security, and what they really do A few specified validation rules get mistaken for protection. The most famous is that fragment spreads must not form cycles: without it, a fragment that spreads itself would let a short document describe an infinitely large selection. That rule exists so that a *finite document text* always expands to a *finite selection*. It is a well-formedness rule, not a cost rule - a legal, acyclic document can still select a million fields. Similarly, fields must exist on the type they are selected against, leaf fields must not carry a selection set and composite fields must, arguments must be of the declared type, and variables must be defined and used. All of these bound *legality*, and they bound it before any resolver runs, which is genuinely useful. None of them bound *work*. ### Introspection is a feature, not a hole the spec left open The specification defines introspection as part of the type system, and describes no mechanism for turning it off. Refusing `__schema` in production is therefore something a server layers on top of the specification, not a configuration the specification anticipates. That matters for the placement discussion: because introspection is just ordinary fields in the schema, a server that wants to refuse it does so with its own rule over the parsed document, in the same place its other document-shaped limits live. ### The transport is a separate document GraphQL deliberately says nothing about HTTP. The conventions everyone shares - `POST` with a JSON body carrying `query`, `variables` and `operationName`; `GET` with the operation in the query string; the `application/json` and `application/graphql-response+json` media types; which status codes accompany which failure - are specified in the *GraphQL over HTTP* working draft, which is a different document and still a draft. The closest thing in the whole ecosystem to a specified security rule lives there: that `GET` should carry only query operations, never mutations. Treat that as near-settled convention with a spec behind it, and say so rather than attributing it to "the GraphQL spec". ### Why the specification's silence is the whole subject Because nothing is specified, every control on a GraphQL endpoint is something you built and attached at a phase you chose. Two conformant servers can behave completely differently under abuse, and a control placed at the wrong point in the pipeline is either uninformed or has already paid for the work it was supposed to prevent. The specification does hand you one enormous gift for security, though, and a good answer says so. A GraphQL request arrives as a *statically analysable document* checked against a *fully typed schema* before a single resolver runs. You can compute a bound on what an operation will ask for without executing any of it - which is exactly what depth caps, field-count caps and cost scores exploit. REST gives you no equivalent: you cannot look at `GET /venues/7813` and know how much of the object graph the handler will walk. So the specification gives you no controls, but it gives you the one property that makes strong pre-execution controls possible at all. ### How to say this in an interview Start with the flat answer - the spec defines no security - then show you know the boundary precisely: type system, validation, execution, response shape are in; identity, budgets and transport are out; the structural validation rules bound legality, not cost; and the typed, pre-executable document is the lever every real control pulls.

  • If the specification defines no depth limit, what stops a self-referencing fragment from describing an infinite selection?
    A specified validation rule: fragment spreads must not form cycles. A fragment may not spread itself, directly or through a chain of other fragments. That guarantees a finite document text always expands to a finite selection set, which is a well-formedness guarantee rather than a cost guarantee - an acyclic document can still select an enormous number of fields, because object types are free to reference one another cyclically in the schema.
  • Which parts of the request/response contract are specified, and which are convention?
    The response *body* shape is specified: a map with `data`, `errors` and `extensions`, with `data` absent when the request failed before execution. The HTTP wrapping is not in the GraphQL spec at all - methods, media types, status codes and the `query`/`variables`/`operationName` body keys are in the separate GraphQL over HTTP working draft. Array-batched bodies, error `code` values under `extensions`, and persisted-document handshakes are pure convention.
  • Does the specification say anything about how errors reveal information?
    It specifies the error entry's shape - a required `message`, plus optional `locations`, `path` and `extensions` - and nothing about what the message may contain. There is no rule that a message must avoid internal detail, no notion of a safe versus unsafe error, and no distinction between an error meant for a client and one meant for an operator. Masking unexpected failures is entirely server policy.

The specification is a grammar and an interpreter manual for a language. A grammar tells you which sentences are well formed; it never tells you who is allowed to speak or for how long.

saying these in an interview costs you the question

  • Claiming GraphQL is secure by default
  • Saying the spec defines a maximum query depth
  • Saying introspection is off by default per the spec
  • Attributing rate limits or cost analysis to the specification
  • Thinking the spec mandates HTTP POST and JSON
  • Assuming the error format is server-specific and unspecified

context

open as a page

Where in GraphQL request handling do content-type checks, depth caps and deadlines each belong?

level: middleimportance: must knowfreq 47%

basics

~20 s

Each control attaches at the earliest phase that has the information it needs. Content-type and body-size checks run before parsing; depth, field-count and cost caps run as validation rules over the parsed document; deadlines and per-object authorization can only run during execution.

open as a page

Why can't per-object authorization be enforced as a GraphQL validation rule?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Validation runs over the document and schema before any resolver executes, so the object does not exist yet. Whether this caller may read this particular order can only be decided once the order has been loaded - during execution.

open as a page

How do you choose which GraphQL abuse controls to run at each phase for a public endpoint?

level: principalimportance: should knowfreq 33%

basics

~20 s

Rank candidate controls by what each phase knows, what each costs on every legitimate request, and how certain each rejection is. Push size, rate and content-type outward, keep document-shaped limits in the service, and treat execution deadlines as the backstop nothing static can replace.

open as a page