Join our Newsletter — 33% off our NHI Course
Home› Guides› REST vs GraphQL Security: Different Attack Surfaces, Different…
Guide Web & API Security

REST vs GraphQL Security: Different Attack Surfaces, Different Controls

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 15 min read
On this page

GraphQL is not less secure than REST, but it moves the attack surface to places that REST-era controls do not look. A REST API spreads risk across many routes, where the classic failures are endpoint sprawl, forgotten versions and broken object level authorisation on one route out of hundreds. A GraphQL API concentrates everything behind one endpoint, where the failures are unbounded queries, batching that defeats rate limits and authorisation that holds on one resolver path but not another. This guide compares the two styles control by control: threat model, where authorisation must sit, why gateways and web application firewalls see less in GraphQL, and which controls each style needs. It is for API architects, AppSec engineers and API security buyers. For GraphQL implementation depth, read the GraphQL Security Guide; for REST-wide basics, the API Security Guide.

Key takeaways

  • Same top risks, different shape. Broken object level authorisation (OWASP API1:2023) and unrestricted resource consumption (API4:2023) hit both styles, but in REST they hide in route sprawl and in GraphQL they hide in resolver paths and query shape.
  • Authorisation belongs below both. graphql.org recommends enforcing authorisation in the business logic layer as a single source of truth; the same layer should serve REST routes, so the two APIs cannot disagree.
  • Request counting breaks in GraphQL. OWASP notes that HTTP-level rate limits count requests, not query cost or batched operations; GraphQL needs depth, breadth, batch and cost limits inside the server.
  • Edge tools see less. A gateway or WAF routes and filters by method and path; in GraphQL the operation, fields and arguments live in the request body behind one URL.
  • Persisted operations change the game. For first-party GraphQL clients, an allowlist of trusted documents is, in graphql.org's words, likely the most effective single control.

Short answer: the two styles side by side

DimensionRESTGraphQL
Entry pointsMany routes and methods, often across versionsUsually one endpoint accepting arbitrary operations against the schema
Unit of workRoughly one request, one resource actionOne request can be many operations, aliases and nested lists
Where authorisation is commonly enforcedRoute or controller, per methodResolver per field, edge and node
Typical discovery riskShadow and zombie endpoints, undocumented versions (API9:2023)Introspection and field suggestions revealing the schema
Resource exhaustion vectorLarge page sizes, expensive endpoints, request floodsDeep nesting, wide aliasing, batched operations
Rate limiting basisRequests per client per route usually worksMust account for query cost and operations per request
Visibility for gateways and WAFsMethod and path identify the actionAction is in the body; path is the same for every call
Over-exposure of dataEndpoints returning full objects (API3:2023)Clients choose fields; sensitive fields need field-level rules
Strongest structural controlComplete inventory plus schema-validated routes (OpenAPI)Trusted documents plus demand control

REST attack surface: threat model and failure modes

Threat model: an attacker enumerates routes, manipulates object identifiers in paths, query strings, headers or bodies, and looks for older or forgotten versions with weaker controls. OWASP API1:2023 describes broken object level authorisation as attackers changing an object ID to reach objects that belong to other users, and calls for object-level checks on every endpoint that takes an object ID. OWASP API9:2023 describes old versions, deprecated endpoints and unneeded hosts left exposed, often found by simple DNS enumeration.

Architecture in words: clients call versioned routes such as /v2/accounts/{id}/statements through an API gateway that authenticates the token, applies coarse rate limits and forwards to services. Each controller or handler is responsible for checking that the caller may perform the method on the specific resource.

  • Endpoint sprawl: hundreds of routes across microservices mean hundreds of places to forget an object check. One missed route is a BOLA. See BOLA vs BFLA.
  • Zombie versions: /v1 stays live after /v2 adds a fix; API9 advises applying external protections to all exposed versions and retiring or backporting.
  • Method confusion: a route allows DELETE or PUT it should not. The OWASP REST Security Cheat Sheet says to allow only approved methods, reject others with 405 and check that the caller may use that method on that resource.
  • Secrets in URLs: tokens or API keys in query strings end up in logs; the cheat sheet says to place them in headers or the body.

GraphQL attack surface: threat model and failure modes

Threat model: an attacker learns the schema through introspection or by guessing from "did you mean" suggestions, then crafts operations that are expensive (deep or wide), batched (many attempts in one request) or that reach a sensitive object through a path the developer did not protect. OWASP's GraphQL Cheat Sheet notes that depth and amount limits "can both be unlimited" by default, which may lead to denial of service.

Architecture in words: clients send operations to a single endpoint such as /graphql; the server parses and validates the document against the schema, then executes resolvers per field. A given object, such as an order, can be reached from a top-level query, through a customer's orders edge, from a search result or by a global node lookup, and each is a separate resolver.

  • Introspection and suggestions: graphql.org notes that disabling introspection is security through obscurity: an attacker can infer the schema from validation errors. Turn off suggestions and mask errors outside development as well.
  • Depth and breadth: nested lists grow results exponentially, and aliasing one field many times multiplies backend calls even in a shallow query. graphql.org recommends a depth limit, a smaller limit for nested lists, and caps on top-level fields and aliases.
  • Batching for brute force: many login or one-time code attempts packed into one HTTP request evade per-request monitoring (ATT&CK T1110 Brute Force). OWASP recommends blocking batching for sensitive objects such as passwords, OTPs and session tokens, and capping operations per batch.
  • Path-dependent authorisation: a check on the top-level query does not protect the same object reached through an edge; OWASP says to enforce authorisation "on both edges and nodes".
  • Cross-site request forgery: the GraphQL over HTTP working draft warns that non-JSON media types such as multipart/form-data can produce simple cross-origin requests that skip browser preflight, and requires that GET never executes mutations.

Where authorisation must sit: route versus resolver versus business layer

REST teams often place authorisation in middleware keyed on route and method. That model maps poorly to GraphQL, where one endpoint serves every action. Putting checks in each resolver works, but graphql.org warns that duplicating logic per entry point means that "if the authorization logic is not kept perfectly in sync, users could see different data depending on which API they use". The durable answer for both styles is the same: enforce authorisation in a business logic or domain layer that REST controllers and GraphQL resolvers both call.

PlacementRESTGraphQLRisk if used alone
Gateway or edgeGood for authentication, coarse scope checks per routeAuthentication only; cannot see fields or objects without parsingNo object-level decisions; BOLA passes straight through
Route middleware or controllerCommon and workable for function-level checksNot applicable: one routeObject checks forgotten on new routes
ResolverNot applicablePer field, edge and nodeInconsistent across paths to the same object
Schema directivesNot applicableDeclarative markers such as @auth on fieldsgraphql.org says logic should still be delegated to the business layer
Business logic layer or object loaderCalled by every controllerCalled by every resolver and node loaderLowest: one source of truth for both APIs
  • Pass a resolved caller, not a token: graphql.org recommends a fully hydrated user object in context, keeping authentication and authorisation in separate stages. The same applies to REST handlers.
  • Fail closed at the object loader: authorise when an object is loaded by ID, so every path (REST route, GraphQL query, edge, node) passes the same check.
  • Batch policy decisions in GraphQL: one query can touch thousands of objects; calling an external policy engine per object will not scale. See the OpenID AuthZEN Authorization API Guide for standardised decision calls.
  • Bind input fields explicitly: REST mass assignment and GraphQL mutation inputs share the same fix: allow only listed fields (OWASP API3:2023, broken object property level authorisation).

Why gateways and WAFs see less in GraphQL

A REST call carries its intent in the method and path: DELETE /v2/users/123 can be routed, logged, rate limited and blocked at the edge. A GraphQL call is usually POST /graphql with the operation in a JSON body. The edge sees the same path for a harmless profile read and a bulk export. The GraphQL Security Guide puts it simply: gateways and WAFs see one GraphQL endpoint, while the operation, fields and arguments live in the body.

  • Signature rules lose context: injection payloads sit inside GraphQL variables, so generic rules either miss them or produce false positives on legitimate query text.
  • Rate limits count the wrong thing: OWASP notes HTTP-level rate limits count requests, not query cost or batched operations. graphql.org recommends rate limiting in the business logic layer because the network layer cannot see field cost.
  • Logs lose meaning: access logs show one URL. Log the operation name, a document hash, cost and the caller in the GraphQL server.
  • What the edge still does well: TLS, authentication, IP reputation, request size limits, blocking GET mutations and enforcing Content-Type: application/json. Some gateways can parse GraphQL; treat that as an extra layer, not a replacement for server-side limits. See WAF vs API Gateway and the API Gateway Security Guide.

Controls per style

RiskREST controlGraphQL control
Discovery of attack surfaceComplete inventory of hosts, versions and environments; restrict documentation to authorised users (API9)Disable introspection and GraphiQL in production; disable field suggestions; mask errors
Unknown or unexpected requestsValidate requests against an OpenAPI schema; reject unknown routes and methods (405)Trusted documents (persisted operations): clients send an ID, the server runs only registered documents
Resource exhaustion (API4)Pagination limits, request size limits (413), 429 rate limiting per clientDepth, list depth, breadth and alias limits; operations per batch; query cost analysis with per-request maximum or client budget; resolver timeouts
Object authorisation (API1)Object check in every handler, via a shared domain layerObject check in the object loader covering every edge and node; remove node/nodes if unused
Property exposure (API3)Response schemas that return only needed fieldsField-level authorisation; interfaces and unions to return different shapes by role
Brute force via the APIPer-route rate limits on authentication endpointsBlock batching for credential and OTP operations; per-object attempt limits in code
CSRF in browser clientsStandard CSRF defences; JSON only for state changesNo mutations over GET (405); require application/json; consider a custom header that forces preflight
Input validation (SI-10)Type, length, range, format checks; 415 for unsupported content typesSchema types plus custom scalars and argument validation; parameterised data access in resolvers

Persisted operations caveat: graphql.org notes trusted documents work best for first-party APIs, since a public API cannot know third-party operations in advance. Public GraphQL APIs rely on cost analysis, per-client budgets and strong authorisation instead. graphql.org also notes efforts to standardise persisted documents in the GraphQL over HTTP specification, which is a working draft as of November 2026, so check the current status before depending on specific wire details.

Decision guidance: choosing and securing a style

  • Public partner or third-party API with stable resources: REST is simpler to rate limit, cache and filter at the edge. Invest in inventory and per-handler object checks.
  • First-party web and mobile clients with complex data needs: GraphQL with trusted documents gives you an allowlist that REST rarely achieves. Without persisted operations, budget for cost analysis and GraphQL-aware testing.
  • Public GraphQL API: possible, but treat cost limits, per-client budgets, error masking and field-level authorisation as launch blockers, not hardening.
  • Running both: common when GraphQL sits in front of REST microservices. Enforce authorisation in the services or domain layer, not only in the GraphQL layer, so a direct call to the REST service cannot bypass it. Federated graphs add the same question at every subgraph: each one must enforce its own object checks.
  • Small teams: REST with an OpenAPI contract and a gateway is easier to secure with fewer specialists. GraphQL demands someone who understands resolver execution and demand control.

Worked scenario: one data model, two APIs

A retailer exposes orders through a REST API for partners and a GraphQL API for its own app.

  1. REST finding: a penetration test finds GET /v1/orders/{id} still live after the /v2 rewrite; /v1 has no ownership check. Fix: retire /v1, add the inventory record, and move the ownership check into the order service so both versions share it.
  2. GraphQL finding: order(id) checks ownership, but search { results { ... on Order } } and node(id) return any order. Fix: authorise in the order loader that every resolver uses, and remove node because the app does not need it.
  3. Abuse finding: the app's login mutation accepts 100 aliased attempts in one request; the gateway rate limit of 10 requests per minute never trips. Fix: block batching and aliasing for authentication mutations and count attempts per account in code.
  4. Prevention: the app's build registers its operations as trusted documents; production rejects anything else. Partner REST traffic is validated against the OpenAPI contract at the gateway.
  5. Result: one authorisation layer, two thin API layers, and edge controls used for what they see well.

Testing, detection and metrics

Test both styles with authorisation-focused test cases: swap object IDs between two test users on every route and every GraphQL path to the same object. OWASP API1 recommends writing tests that evaluate the authorisation mechanism and blocking deployments that fail them. For GraphQL, add tests that send over-depth, over-breadth and over-batch operations and confirm rejection before execution. See the API Security Checklist and Rate Limiting and API Abuse Guide.

  • Inventory coverage: percentage of live REST hosts and versions, and GraphQL endpoints, recorded in the API inventory with an owner.
  • Authorisation test coverage: percentage of routes and GraphQL object types with automated cross-tenant or cross-user tests in CI.
  • Rejected operations: count of GraphQL operations rejected for depth, cost, batch size or unknown document, per client, trended over time.
  • Introspection and suggestion exposure: number of production GraphQL endpoints answering introspection (target zero for private APIs).
  • Zombie version count: deprecated REST versions still receiving traffic past their retirement date.
  • Cost budget breaches: clients exceeding their GraphQL cost budget, investigated as potential abuse.

Where identity fits

Most API callers are not people: mobile app instances, partner integrations, internal services and, increasingly, AI agents, each holding an API key or OAuth token. Scope tokens to the operations they need, bind GraphQL trusted documents and cost budgets to the client identity, and pass the originating user alongside a service identity when a service calls on someone's behalf. See the OAuth 2.0 and OpenID Connect Guide.

Framework mapping

FrameworkReferenceREST and GraphQL relevance
OWASP API Security Top 10 2023API1 Broken Object Level Authorization; API3 Broken Object Property Level Authorization; API4 Unrestricted Resource Consumption; API5 Broken Function Level Authorization; API9 Improper Inventory ManagementCommon risk set for both styles
NIST SP 800-53 Rev 5AC-3 Access Enforcement; AC-6 Least PrivilegeObject, field and function authorisation
NIST SP 800-53 Rev 5SC-5 Denial-of-service Protection; SI-10 Information Input Validation; CM-8 System Component InventoryDemand control, input validation, API inventory
NIST CSF 2.0PR.AA-05; ID.AM-02Authorisation policy and inventories of services
MITRE ATT&CK v20T1190 Exploit Public-Facing Application; T1110 Brute Force; T1595 Active ScanningAPI exploitation, batched credential attacks, endpoint and schema discovery

Common failure patterns

  • Porting REST middleware to GraphQL: a route-based check on /graphql authorises everything or nothing.
  • Relying on the gateway rate limit for GraphQL: one request can carry hundreds of operations or a query that costs thousands of backend calls.
  • Disabling introspection and calling it done: suggestions and errors still leak the schema, and authorisation gaps remain.
  • Authorising the top-level field only: the same object leaks through an edge, a search result or node.
  • Forgetting REST versions: the new version is hardened; the old one still answers and shares the same database.
  • GraphQL over REST with checks only in GraphQL: the backing REST services trust any internal caller, so a compromised service or token bypasses every rule.

Practitioner checklist

  • Move object and field authorisation into a shared domain layer or object loader used by both REST handlers and GraphQL resolvers.
  • Keep a complete inventory of REST hosts and versions and of GraphQL endpoints, with owners and retirement dates.
  • Disable introspection, GraphiQL and field suggestions in production for private GraphQL APIs, and mask errors.
  • Set depth, list depth, breadth, alias and batch limits, and add cost analysis where clients can write arbitrary queries.
  • Use trusted documents for first-party GraphQL clients.
  • Block batching for credential, OTP and session operations.
  • Reject GET mutations and require application/json for GraphQL; restrict REST methods per route with 405.
  • Add cross-user authorisation tests for every route and every GraphQL path to sensitive objects, and fail the build on regressions.
  • Log GraphQL operation name, document hash, cost and caller identity, not just the URL.

Standards and references

Related NHI Mgmt Group resources: GraphQL Security Guide, API Security Guide, BOLA vs BFLA, WAF vs API Gateway, Rate Limiting and API Abuse Guide.

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.