GraphQL has become widely adopted in modern application development. However, it also creates security challenges that many conventional testing methods were not designed to detect.
Proper security assessment requires a detailed understanding of how GraphQL APIs operate in real-world environments. This guide describes the primary security risks, testing methods, and operational factors involved in protecting GraphQL APIs.
Why Does GraphQL Present Challenges for Traditional Security Testing?
REST APIs normally use a separate URL for each endpoint. By contrast, GraphQL commonly exposes only one endpoint capable of processing numerous queries and mutations. As a result, the testing scope extends far beyond the URL itself. It also includes the schema, the underlying resolver logic, and the authorization rules applied to every type, field, and operation. Unlike Invicti, which is based on Acunetix and Netsparker, a DAST scanner that recognizes /graphql only as a single endpoint may fail to identify the actual complexity behind it.
Attackers can use introspection, field suggestions, or schema reconstruction techniques to identify available types, fields, queries, and mutations. After reconstructing or obtaining the schema, they can search for unnecessarily exposed fields, insecure object access, batching abuse, excessive query complexity, and injection vulnerabilities within resolver logic.
Security Testing of GraphQL APIs
Schema Discovery and Analysis
Identify all accessible queries, mutations, subscriptions, types, fields, arguments, and relationships. This information may be obtained through introspection, schema files, traffic inspection, or schema reconstruction.
The schema forms the basis of GraphQL security testing. It specifies which operations are available, which inputs they accept, which objects they return, and how those objects are connected.If attackers gain access to the schema, it can serve as a map for locating sensitive fields, undocumented functionality, weak authorization paths, and resource-intensive queries.
Security testing should address several fundamental questions:
- Can schema information be retrieved without authentication?
- Can a user with limited privileges obtain schema details intended only for internal access?
- Are sensitive types, deprecated fields, administrative mutations, or internal object relationships exposed?
- Does the schema contain accessible fields that are no longer used by the front-end application?
- Does the API documentation accurately reflect the live schema?
Differences between documented behavior and the live implementation require particular attention. GraphQL APIs often change rapidly, and obsolete fields or mutations may remain available even after the user interface has stopped using them.
Introspection Abuse
Determine whether GraphQL introspection remains enabled in production. Alternative methods of schema disclosure should also be examined.
An introspection query allows a GraphQL API to describe its schema. This information may include available types, fields, queries, mutations, and subscriptions. Introspection is highly useful during development. However, unrestricted introspection in a production environment can provide attackers with a detailed roadmap of the application. Testing should establish whether introspection has been disabled or restricted appropriately. When standard introspection is blocked, field suggestions and detailed error messages should still be checked for schema leakage.
Some implementations return hints such as “Did you mean customer email?” These suggestions can help attackers reconstruct the schema even when formal introspection is unavailable.
GraphQL Query Exploitation
Modify GraphQL queries to identify over-fetching, abuse of nested queries, complexity-based attacks, batching attacks, and unauthorized access to data.
GraphQL allows clients to request precisely the information they require. However, this flexibility can also be exploited. Attackers may request fields that are never displayed by the front-end application. They may also create deeply nested relationships to increase backend processing or combine numerous operations within one request. Such techniques may bypass controls designed to evaluate individual HTTP requests.
Testing should cover both data exposure and resource exhaustion.
For data exposure testing, sensitive fields should be requested through different object relationships and alternative query paths. For resource-consumption testing, deeply nested queries, repeated fragments, circular relationships, and expensive resolver combinations should be evaluated. These techniques may consume excessive CPU resources, memory, database capacity, or downstream service calls.
Important security controls requiring validation include:
- Depth limits that prevent excessively nested queries
- Query-cost analysis that accounts for expensive fields and resolver behavior
- Timeout controls for slow or resource-intensive operations
- Rate limiting applied to individual GraphQL operations rather than only to HTTP requests
- Persisted queries where appropriate, particularly for high-risk production APIs
Persisted queries can reduce exposure by allowing only preapproved operations to execute instead of accepting arbitrary client-supplied queries.
This approach is most suitable for tightly controlled production environments where reduced query flexibility is acceptable. Persisted queries do not replace authorization controls or schema protection. However, they can substantially limit opportunities for schema exploration and query abuse.
Batching Attacks
Determine whether GraphQL batching can be exploited to circumvent rate limits, perform credential brute-force attacks, or enumerate identifiers.
GraphQL batching allows a client to submit several operations within a single HTTP request. This feature can improve performance for legitimate clients. At the same time, it can weaken security controls that count HTTP requests without considering the number of operations inside them. For example, a login mutation may be rate-limited according to the number of HTTP requests. However, hundreds of authentication attempts may still be possible if they are combined into one batched request.
Testing should establish whether the API supports batched queries or mutations. It should also examine how security controls behave when several operations are submitted simultaneously. Special attention should be given to authentication, password-reset, invitation, coupon, search, and object-lookup operations. These operations are frequently targeted during brute-force and enumeration attacks. Effective protection must enforce restrictions at the operation level rather than only at the HTTP-request level.
Monitoring, logging, rate limiting, account-lockout policies, and anomaly-detection mechanisms should recognize every individual operation contained within a batch. When batching is supported, strict restrictions should be applied to batch size, operation count, execution cost, and authentication-sensitive mutations.
Authorization and Access-Control Testing
Confirm that each user can access only the information and operations permitted by the assigned role, object ownership, tenant membership, and relevant business context.
Authorization is particularly complex in GraphQL because access controls may be required at the operation, object, field, and resolver levels. Protecting the graphql endpoint alone is insufficient. A user may be authorized to execute a query but may not be entitled to view every field returned by that query. Testing should include broken object-level authorization, or BOLA, insecure direct object references, or IDOR, field-level authorization bypasses, and tenant-isolation failures.
Several accounts with different roles, permissions, organizations, and ownership relationships should be used during testing. Identifiers, nested relationships, filters, aliases, and alternative query paths should then be manipulated to determine whether data can cross established authorization boundaries.
Field-level authorization requires dedicated attention. The same sensitive field may be accessible through several different paths. For example, an application may correctly conceal a salary, SSN, API key, or internal notes field in one query. However, the same field may remain exposed through a nested employee, account, organization, or auditLog relationship elsewhere in the schema. Access controls must remain effective across every possible path, not only through the primary operation used by the front-end application.
Authorization testing must also cover mutations. Users should not be able to create, modify, delete, approve, transfer, invite, or assign resources beyond the permissions of their role or tenant. A GraphQL mutation may initiate several backend actions. Consequently, both the direct API response and the resulting changes in application state must be examined.
Race conditions and check-then-act authorization weaknesses should also be included in the assessment. Concurrent mutations can sometimes bypass business rules that appear secure when tested individually. This risk is particularly relevant when ownership verification, balance validation, or approval processes are involved.
Subscription Operations
Assess GraphQL subscriptions for authorization weaknesses, data leakage, connection-management issues, and denial-of-service risks.
Subscriptions allow clients to receive real-time updates through a persistent connection, most commonly over WebSockets. Queries and mutations are generally tested more extensively because they follow a standard request-response model. Subscriptions often receive less attention. Nevertheless, they can disclose sensitive events and create separate operational risks. Security testing should confirm that proper authentication is required when the connection is established. Appropriate authorization must also be enforced when a subscription is created.
Authorization should be reassessed when user permissions change, tokens expire, accounts are disabled, or tenant membership is modified.
Testing should identify whether event streams can be exposed across different tenants or user roles. Identifier and filter manipulation should not allow access to updates belonging to another customer. Resource-management controls should also be validated. These controls include connection limits, idle timeouts, and message-size restrictions. Proper enforcement helps reduce the risk of denial-of-service attacks.
Injection Testing in GraphQL
Check query arguments, variables, resolver inputs, and backend service calls for injection vulnerabilities.
GraphQL itself is not a database query language. However, GraphQL resolvers frequently communicate with databases, search platforms, command-line utilities, internal APIs, message queues, and cloud services. If resolver inputs are not validated and processed securely, attackers may be able to exploit SQL injection, NoSQL injection, command injection, LDAP injection, server-side request forgery, or unsafe deserialization through GraphQL operations.
Testing should cover both inline arguments and variables. Variables are particularly significant because production clients often use parameterized GraphQL operations accompanied by JSON variables. Vulnerable resolver logic may therefore be hidden behind queries that otherwise appear legitimate.
Relevant testing areas include:
- String arguments used for filtering, searching, sorting, or locating objects
- Numeric arguments used for limits, offsets, prices, quantities, or identifiers
- Enum values and default branches within resolver logic
- Custom scalars that accept JSON-like data
- File-upload functionality
- URLs, file paths, and callback values passed to backend services
The objective should not be limited to determining whether the GraphQL layer produces an error.
Backend behavior should be examined whenever possible. Relevant indicators include database errors, timing variations, out-of-band callbacks, unexpected state changes, and inconsistent validation between different resolvers.
Conclusion
GraphQL APIs provide powerful capabilities for modern application development. At the same time, they introduce attack paths that traditional security-testing methods frequently fail to detect.
Organizations that continue to assess GraphQL in the same way as conventional REST APIs may overlook substantial parts of their attack surface.
Invicti, based on Acunetix and Netsparker, can be used to test GraphQL APIs for vulnerabilities automatically and accurately. A free trial can be requested by submitting contact details through the form below. A representative will then provide further information.







