GraphQL Authorization Mistakes to Detect
Detect GraphQL authorization mistakes — BOLA argument manipulation, introspection exposure, and query-level-only checks, with Sigma rules and hardening.
GraphQL authorization fails in a specific, predictable way: the API checks “are you
logged in?” at the query level but never “do you own this object?” at the field and
object level. A client composes its own query, swaps in another user’s id, and
the resolver hands back data it should have refused. This is Broken Object Level
Authorization, and it is the GraphQL authorization mistake you most need to detect.
This guide ships the detection logic and the resolver-level controls that close it.
GraphQL’s flexibility widens the attack surface — aliases, nested selections, batched mutations — so REST-era, route-based authorization stops applying. BOLA maps to OWASP API1:2023 and MITRE ATT&CK T1190 / T1078. The 2025 Parse Server flaw CVE-2025-53364 — public, unauthenticated access to the GraphQL schema — is the worked example.
What is a GraphQL authorization mistake?
A GraphQL authorization mistake is any gap that lets a client reach data or
operations it should not. Because the client composes the query, a single endpoint
exposes the whole graph — so authorization has to be enforced per object and per
field in the resolvers, not at a route. The most common and damaging gap is BOLA:
the resolver trusts a client-supplied id argument without checking ownership.
This is the same class as broken access control in REST, expressed through GraphQL arguments. The detection philosophy carries over too: authorization decisions are events, and abuse has a shape.
What are the most common GraphQL authorization mistakes?
| Mistake | What the attacker does | Telemetry fingerprint | Defense |
|---|---|---|---|
| Query-level-only authz (BOLA) | Swaps id arguments to read others’ data | One actor, many distinct object IDs | Object/field-level authz |
| Broken function-level authz (BFLA) | Calls admin queries/mutations as a low role | Low-role actor hitting privileged operations | Role checks per operation |
| Introspection exposure | Maps the full schema, finds hidden fields | Introspection query, esp. unauthenticated | Control/auth introspection |
| Alias / batch abuse | Aliases to brute force or batch many objects | Many aliased fields in one operation | Depth/cost limits, rate limiting |
The unifying lesson: GraphQL authorization is per-object and per-field, and the detection signal is one actor pulling far more of the graph than their role should — through arguments, aliases, or batches.
How to detect GraphQL authorization abuse
The prerequisite is logging GraphQL operations with the actor, operation name, and arguments — without that, the API is a black box. With it, two patterns surface.
Unauthenticated introspection queries
An introspection query (__schema, __type) from an unauthenticated or low-trust
client is schema reconnaissance.
title: GraphQL Introspection Query From an Unauthenticated Client
id: 4c9e2b71-darkpwn-illustrative
status: experimental
logsource:
product: application
service: graphql
detection:
selection:
query|contains: ['__schema', '__type', 'IntrospectionQuery']
filter_authed:
auth_state: 'authenticated'
condition: selection and not filter_authed
falsepositives:
- Developer tooling/playground in non-prod (disable introspection in prod)
level: medium BOLA enumeration via argument manipulation
A single actor pulling many distinct object IDs through query arguments is the BOLA signature — the GraphQL form of the object-ID enumeration seen in REST.
index=app sourcetype=graphql:operation
| rex field=arguments "id\"\s*:\s*\"(?<obj_id>[^\"]+)\""
| bin _time span=5m
| stats dc(obj_id) AS distinct_ids by _time, actor_id, operation_name
| where distinct_ids >= 50 How to test your GraphQL authorization
In a staging API you own:
- As user A, request user B’s object IDs through query arguments; every one should be denied, not returned.
- As a low-privilege role, call an admin query/mutation; it should be refused.
- Send an introspection query unauthenticated; confirm it is blocked and alerts.
- Send an alias/batch operation pulling many objects; confirm the cost/depth limit and the enumeration alert both trip.
How to defend against GraphQL authorization mistakes
- Layer the other controls (per Escape/StackHawk guidance): query allowlisting, depth and cost limits, GraphQL-aware rate limiting, and CSRF protection. No single control is enough.
- Control introspection — disable it in production unless you truly need it, and never expose it unauthenticated.
- Validate and bound inputs — reject overly nested or expensive operations before they execute.
Common GraphQL detection mistakes
- No operation/argument logging. The single endpoint hides everything; you must log the operation and arguments.
- Request-count thresholds only. Aliases and batching defeat them — count objects per request.
- Treating introspection-off as the fix. The gap is missing authz, not the feature.
- Reusing REST route rules. GraphQL needs object/field-level checks.
GraphQL authorization checklist
- Enforce object- and field-level authorization in resolvers, scoped to the principal.
- Add RBAC/role checks on privileged queries and mutations (BFLA).
- Disable introspection in production; never expose the schema unauthenticated.
- Apply query depth limits, cost analysis, and GraphQL-aware rate limiting.
- Allowlist known operations (persisted queries) where feasible.
- Log every operation with actor, operation name, and arguments.
- Alert on object-ID enumeration, alias/batch fan-out, and unauthenticated introspection.
- Test cross-user argument access and admin-operation access per role in CI.
The takeaway
GraphQL authorization mistakes are REST’s broken access control wearing a new syntax: authorize per object and per field in resolvers, control introspection, and bound query cost. Detect by logging operations and arguments and alerting on the actor who pulls more of the graph than their role should. Pair this with broken access control testing and JWT misconfiguration detection for full API-security coverage, or browse the Detection Engineering pillar.
Training & tools referenced
Disclosure: Some links below are affiliate links. If you buy through them, darkpwn may earn a commission at no extra cost to you. We only recommend training and tools we actually use in our own lab, and affiliate links never influence editorial coverage.
- TryHackMeAuthorized labs to practice API and GraphQL authorization testingSecurity TrainingStart training
Frequently asked questions
What is the most common GraphQL authorization mistake?
Checking authorization only at the query level instead of the object and field level. A user passes another user's id as an argument and the resolver returns the object without verifying ownership — Broken Object Level Authorization (BOLA). The fix is field- and object-level authorization enforced in resolvers.
Should you disable GraphQL introspection?
For private APIs you do not need introspection, so turning it off reduces schema disclosure. But introspection is not the real problem — missing authentication and authorization around it is, as CVE-2025-53364 showed. Control access to introspection rather than relying on disabling it alone.
How do you detect GraphQL authorization abuse?
Log GraphQL operations with the actor, operation name, and arguments, then alert on a single actor requesting many distinct object IDs via argument manipulation (BOLA enumeration), alias-based brute force, and introspection queries from unauthenticated clients.
What is BOLA in GraphQL?
BOLA (Broken Object Level Authorization) is when the API trusts a client-supplied object id without checking the requester owns it — the same flaw as IDOR in REST. In GraphQL it appears as argument manipulation on queries and mutations and maps to OWASP API1.