GraphQL API security risks every developer should know about

Wiz Expertenteam

What is GraphQL API security?

GraphQL API security is a set of specialized practices and controls for protecting GraphQL endpoints. It focuses on mitigating risks and vulnerabilities inherent to GraphQL’s flexible nature and unique architecture, such as over-fetching, excessive query complexity, injection issues, schema introspection misuse, and query depth exploitation.

What makes GraphQL security different

In contrast to RESTful APIs, which are typically resource-oriented, GraphQL is schema-driven and built around the following core components:

  • Schemas: Blueprints that specify the structure of data and the operations clients can perform

  • Resolvers: Functions responsible for reading, creating, updating, or deleting data for given schema fields

  • Queries, mutations, and subscriptions: Core operations for retrieving data, modifying data, or receiving push updates, respectively

GraphQL capabilities are typically exposed through a single HTTP endpoint (e.g., https://api.yourdomain.com/api/graphql) that often supports POST (and sometimes GET for queries or persisted queries) with client-controlled queries in the request. Then, what’s in the body determines how the data is accessed or modified according to the schema. 

These extremely flexible querying capabilities are a major advantage, but they also introduce security challenges. Since this model allows an unlimited number of valid input queries, it can be exploited if it’s not properly controlled.

The bottom line? GraphQL requires technical defenses beyond common REST API security best practices. But before we look at protections, let’s take a closer look at attack vectors.

Advanced API Security Best Practices [Cheat Sheet]

Download the Wiz API Security Best Practices Cheat Sheet and fortify your API infrastructure with proven, advanced techniques tailored for secure, high-performance API management.

Main GraphQL vulnerabilities and attack vectors

OWASP, GraphQL.org, and Apollo highlight pressing security risks that affect GraphQL APIs:

Authorization issues

In GraphQL, clients are free to craft the queries they want. But this versatile query structure makes it more difficult to implement role-based access control (RBAC) than in traditional REST APIs.

Without strict field-level authorization, sensitive information may be exposed, even when higher-level access rules are enforced (e.g., a user allowed to query their profile might still be able to access or manipulate hidden fields like role, if those aren’t restricted).

This freedom in data fetching also creates fertile ground for insecure direct object reference (IDOR) attacks. After all, a common GraphQL pattern is to use a root-level field that accepts an identifier (such as an id) to fetch a specific object. For example:

query GetCompanyDetails($companyId: ID!) {
  company(id: $companyId) {
    name
    email
  }
}

What happens if the resolver for the company field doesn’t enforce proper authorization checks? An attacker could increment the $companyId from their authorized value (e.g., 100) to another value (e.g., 101) and gain access to data they shouldn’t have access to.

Denial-of-service threats

Another big risk to keep in mind? GraphQL’s flexibility means it can be abused for denial-of-service (DoS) attempts:

  • Attackers can produce intentionally over-nested queries or queries with circular dependencies that cause excessive resolver calls. The result? An overwhelmed server that quickly exhausts its resources.

  • Query batching can reduce the effectiveness of naive rate limiters by letting malicious users combine multiple expensive operations into a single request, helping them bypass rate limiters. Considering that GraphQL backends typically expose only one endpoint, devising effective rate limiting is challenging. 

  • Attackers can also exploit alias-based amplification, disguising repeated costly operations under different field aliases.

  • Another tactic involves sending so-called “complexity bomb” queries. In this case, attackers study your public GraphQL schema to form queries that look simple on the surface but require heavy computation on the backend.

Schema introspection and data over-exposure

Through the introspection feature, users can write special queries to learn about the GraphQL API schema (e.g., discovering available types, fields, and operations). That’s helpful for developers—and, you guessed it: It also introduces some GraphQL vulnerabilities.

Bad actors could easily exploit introspection queries to perform schema discovery attacks, with the goal of identifying private data types, undocumented fields, administrative functions, and more. They can write highly targeted queries to trigger data leaks, denial-of-service attacks, and other exploits.

Remember: The exposure of users’ personal data can be a major compliance issue. Violations of privacy regulations like GDPR and CCPA can result in substantial fines.

Information disclosure through error handling

Just like in REST APIs, GraphQL endpoints can inadvertently leak sensitive information through improper error handling. When an invalid query is submitted, a poorly configured server might return verbose error messages that reveal information about the underlying tech stack or parts of the schema.

For instance, an error like "Cannot query field 'userRole' on type 'Query'. Did you mean 'role'?" reveals the existence of the role field name. Similarly, an error such as "Cannot query field 'salary' on type 'User'" exposes the existence of a salary field, even if it’s restricted for access.

Threat actors who spot error handling flaws can start sending automated, randomized queries and analyze error responses to find out as much as possible about your GraphQL schema—and then use what they discovered against you.

GraphQL injection attacks

Because of its open-input nature, GraphQL is particularly susceptible to classic injection attacks. In fact, injection attacks are some of the most commonly documented GraphQL breaches.

Users’ ability to control query inputs opens the door to a wide range of issues, including:

  • SQL injection, which can occur if an argument is directly concatenated into a database query string. To prevent this, always prefer parameterized queries or prepared statements instead of string concatenation.

  • Command injection, which arises if a resolver uses a user-supplied string to execute a system command on the server. This risk can be reduced by avoiding direct shell calls and validating inputs against strict whitelists.

  • Prompt injection, where user-supplied input is inserted into dynamically generated AI prompts to alter their intended behavior. Mitigate this issue by separating user input from system instructions, sanitizing input, and applying guardrails to restrict what AI is permitted to do.

CSRF on mutation operations

Cross-site request forgery (CSRF) happens when a malicious website deceives a browser into executing unintended actions on a trusted site where the user is already logged in. This GraphQL vulnerability often involves mutation operations, but query operations that trigger side effects in misdesigned systems can also be abused.

GraphQL backends are particularly susceptible to CSRF because of their single and predictable POST API endpoint. A bad actor could embed a hidden JavaScript script in a malicious website that sends a crafted mutation to the GraphQL API endpoint. When an authenticated user visits the attacker’s page, their browser automatically includes session cookies, sending a request to the GraphQL backend as if it came from the legitimate user.

General API security flaws

The simple fact that GraphQL backends are API backends means they’re subject to all common API security risks. These include authorization bypass, broken authentication, broken object-level authorization, unrestricted access to sensitive business flows, server-side request forgery (SSRF), general security misconfigurations, and cross-site attacks (XSS).

GraphQL security best practices

Now that we’ve covered the threats, read on for actionable API security best practices for GraphQL backends:

Security issueSecurity issue categoryBest practice
Exposure of sensitive fields, IDOR, broken object-level authorizationAuthorization issuesField-level access control
Unauthorized access, privilege escalationAuthorization issuesContext-aware access control
Unauthorized mutation execution via CSRFCSRF on mutation operationsAccept only “preflighted” requests and enforce CSRF tokens, SameSite cookies, and Origin/Referer checks
SQL injection, command injection, prompt injectionGraphQL injection attacksUse parameterized queries/ORMs
Resource exhaustion from nested or complex queriesDenial-of-service threatsQuery depth and complexity limits
Arbitrary queries and data over-exposureQuery control and data exposurePersisted queries/allow-lists (APQ)
Expensive queries that overwhelm the serverDenial-of-service threatsTimeout and resource limits
Server overload via single endpoint abuseDenial-of-service threatsCost-based rate limiting and caching
Schema exposure and targeted attacksOver-fetching / information disclosureRestrict or disable introspection in production
Accidental vulnerabilities and insecure schemaOver-fetching / general API security flawsVersion control and schema documentation
Broken authentication, authorization bypass, XSS, SSRF, misconfigurations, stack trace exposure, etc.General API security flaws, information disclosure through error handlingFollow Apollo, OWASP, and GraphQL.org guidelines

Authorization and access control frameworks

  • Field-level access control: To guarantee that users can only access or modify permitted fields, GraphQL authorization needs to be built around field-level access control. Leverage tools like graphql-shield for help applying these rules across resolvers. Example:

const { rule, shield } = require('graphql-shield');

// define a rule to check if the user is an admin
const isAdmin = rule()((parent, args, ctx) => ctx.user.role === 'admin');

// apply the rule to specific fields
const permissions = shield({
  Query: {
    secretData: isAdmin,
  },
});
  • Context-aware access controls: To stop unauthorized access, consider user roles, request behavior, and other contextual information. Pro-tip: OWASP tooling, such as the InQL Scanner, can help validate authorization gaps and context-aware access controls.

  • CSRF protections: GraphQL backends need CSRF protections to stop unauthorized queries and mutations. Servers should refuse to execute any operation originating from a browser that hasn’t “preflighted” the request.

Query analysis and execution limiting

To control query complexity and prevent DoS…

import express from 'express';
import { createHandler } from 'graphql-http';
import depthLimit from 'graphql-depth-limit';
import { schema } from './schema.js'; // import your GraphQL schema

const app = express();

// register GraphQL middleware for a maximum query depth of 5
app.use(
  '/api/graphql',
  createHandler({
    schema,
    validationRules: [depthLimit(5)],
  })
);
POST /api/graphql
{
  "id": "a1b2c3d4",   // hash of the whitelisted query
  "variables": { ... }
}
  • Apply timeout controls and resource limits to individual operations. This way, legitimate but expensive queries will be killed before overwhelming the server, protecting against DoS threats.

GraphQL rate limiting

Even a single request can overwhelm a server, so traditional rate limiting by IP address or user session is insufficient for GraphQL. Instead, production-ready GraphQL rate limiting takes a more granular approach based on query cost analysis

This method assigns a cost to each field to control how much “complexity” a user can consume per session. Caching can further reduce server load, enabling higher overall rate limits without compromising performance.

Schema security

Apollo recommends always disabling GraphQL introspection in production to prevent attackers from using the schema as a roadmap for reconnaissance.

Another top tip? Remember that GraphQL schemas need to be treated as a fundamental part of your AppSec procedures. They should be managed with version control, well-documented, and put through frequent review.

General production hardening

For other GraphQL API security best practices, refer to these resources:

Testing and monitoring GraphQL APIs for security gaps

To achieve strong GraphQL security, teams should adopt a layered approach across the entire API lifecycle. Here are some quick guidelines you can follow:

How Wiz helps secure GraphQL APIs

As we’ve seen, GraphQL’s architecture can lead to unique attack vectors: After all, a single misconfigured resolver or a poorly secured GraphQL endpoint can expose your entire infrastructure to serious threats.

The big takeaway? To safeguard GraphQL backends, you need a unified solution like Wiz Cloud

Wiz Cloud takes a multi-layered approach to GraphQL API security:

  • Discovery: Thanks to runtime sensors, API gateways, management tools, and API specifications, Wiz automatically discovers your GraphQL endpoints. This enables you to maintain a complete inventory of API endpoints, including those unintentionally exposed to the public.

  • Risk assessment: The Wiz Dynamic Scanner probes your GraphQL endpoints to uncover misconfigurations, insecure schemas, and other vulnerabilities. It also evaluates public exposure and potential attack paths to help you understand and prioritize real-world risks.

  • Uncovering toxic combinations: Wiz goes beyond surface-level scanning. By contextualizing API risks together with characteristics like sensitive data exposure, authorization flows, and hosting resources, it identifies chains of issues that attackers could exploit to compromise your GraphQL infrastructure.

Figure 1: The Wiz Dynamic Scanner in action

TL;DR? Count on Wiz for:

  • A comprehensive API endpoint inventory

  • External exposure detection and alerting

  • GraphQL schema analysis and validation

  • Sensitive data discovery and scanning

  • Authorization header scanning

  • Authorization misconfiguration detection

  • API performance and security metrics

  • Hosting resource mapping

  • A unified API security dashboard

See it in action: Schedule a demo to discover your GraphQL endpoints automatically, visualize their code-to-cloud context, and prioritize the fixes that matter.

Agentless, contextual API discovery

Wiz helps teams quickly uncover every API in their cloud environment, known and unknown, and see their exposure with full execution context. This makes it simple to answer: What APIs do I have, and where are they running?

Informationen darüber, wie Wiz mit Ihren personenbezogenen Daten umgeht, finden Sie in unserer Datenschutzerklärung.