Flexibility is part of the attack surface

GraphQL lets the client choose the response shape. The server therefore cannot infer cost from the endpoint alone. A shallow query with many aliases or large pages may consume more work than a deeply nested but narrow tree.

Depth limits are useful, but a cost model is stronger: assign weights to expensive fields, cap page sizes and result counts, and stop execution when the request exceeds a budget. Associate that budget with identity or application, not only IP address.

Authorization belongs at every data path

A check at the root query does not authorize every nested node. If a resolver returns related records without verifying ownership, the schema exposes object-level authorization bugs through a convenient alternate path.

Apply the same policy contract to nodes, edges, mutations, unions, and batch loaders. DataLoader-style optimization should not merge requests across security contexts or return cached objects to another user.

  • Set maximum page sizes and total object counts.
  • Constrain aliases and batching on sensitive operations.
  • Avoid detailed stack traces and internal error messages.
  • Disable public schema exploration tools when the threat model does not require them.

Observe actual cost

Record estimated versus real execution cost, resolver latency, and datastore calls. That data helps distinguish a demanding legitimate query from abuse and lets the budget evolve with the schema.

GraphQL security is not one switch. It is the alignment of schema design, object authorization, and resource budgets so flexibility remains a product advantage rather than an unmetered compute interface.

← Back to the archive