GraphQL Hacking 101: Vulnerabilities from the Attacker’s Perspective
10 min read Cybersecurity / API Security Enis

GraphQL Hacking 101: Vulnerabilities from the Attacker’s Perspective

In today's applications, communication with APIs has become more critical than ever. To meet this need, new and flexible technologies like GraphQL have entered our lives, alongside established solutions like REST. In this article, we will focus speci...

In today's applications, communication with APIs has become more critical than ever. To meet this need, new and flexible technologies like GraphQL have entered our lives, alongside established solutions like REST. In this article, we will focus specifically on GraphQL and try to understand how vulnerabilities in this technology are exploited from the perspective of a bug bounty hunter, a cybersecurity researcher, or an attacker. Let's dive into this important topic together.

Before we begin, I want to state that all examples and screenshots in this article were conducted in a controlled sandbox environment for purely educational purposes. No live systems were harmed. Our goal here is not to encourage an attacker's approach, but quite the opposite: to build more secure systems by understanding how attackers think and act. The first step in defense is knowing the potential attack vectors.

enis.gif

What is GraphQL and Why is it Used?

ayrac.png

What is GraphQL?

7402UV0.png

GraphQL is a query language developed by Facebook and open-sourced in 2015. It was developed as an alternative to REST APIs and allows clients to query the data they need in a more flexible and efficient way.

Key Features

Flexibility: Clients can query the specific pieces of data they need.

Efficiency: Data from multiple sources can be retrieved with a single request.

Type Safety: The GraphQL schema defines data types and relationships, allowing clients to know in advance what data they can access.

aTg2fii.png

To understand why GraphQL is important, we need to understand where and why it is used. Therefore, I want you to read the following sections and question them internally to make sense of them.

GraphQL is widely used on both mobile and web platforms. It is preferred because it allows clients to fetch only the necessary data, preventing the large data blocks often received with REST APIs that clients don't need. It also stands out with features like its ability to combine data from different sources in a single query, easier integration with its self-documenting API structure, powerful developer tools, and optimizing data transfer and processing times by allowing clients to query specific data fragments.

gQwbQJA.png

Basic Queries

ayrac.png

GraphQL generally supports GET and POST methods for its queries. One of these queries, Introspection, is used to reveal schema information and helps an attacker understand the structure of the target system. While it is an invaluable tool during development, leaving it enabled in a production environment is equivalent to handing an attacker a map of your entire API, including potential weaknesses and data structures. From an attacker's perspective, introspection queries are like a treasure map; by obtaining the schema that defines the API's data types, fields, arguments, and relationships, you can easily identify paths to sensitive data. This makes it much simpler to plan effective attacks during the reconnaissance phase, such as unauthorized data retrieval or DoS attacks. Developers often forget to disable this in production, or controls are insufficient in APIs that allow anonymous access. A similar issue occurred in Red Hat GraphQL as CVE-2024-50312, where unauthorized users could access schema information. CVE-2025-53364 in Parse Server shows that even disabling it can sometimes be insufficient.

Example Queries

To find the names of all types:

{__schema{types{name}}}

Ekran görüntüsü 2025-09-10 072310.png

To list all fields and their arguments:

{
  __schema {
    types {
      name
      fields {
        name
        args {
          name
          description
          type {
            name
            kind
          }
        }
      }
    }
  }
}

Ekran görüntüsü 2025-09-10 072859.png

Inspecting Errors

Error messages can provide significant clues about the system. To trigger error messages, send invalid queries:

{olmayanbirdeger}

image (5).jpg

From an attacker's point of view, inspecting errors opens the door to information leakage; detailed messages from the server in response to invalid queries can reveal secrets like the database type or library versions. This provides an excellent foundation for more complex attacks, such as immediately seeing success when testing for SQL injections. These types of problems are common if error messages are not hidden in production or if development settings are carried over to the live environment. CVE-2021-4191 in GitLab is a great example of how information leakage in GraphQL APIs can be used to enumerate user information.

Data Extraction

After learning the schema and fields, data extraction operations can be performed. For example, if there is a "user" object, the following query can be used to retrieve its values:

{
  user(id: "1") {
    id
    name
    email
  }
}

Ekran görüntüsü 2025-09-10 074217.png

Data extraction is the "harvesting" phase after introspection. The attacker queries the fields learned from the schema to extract sensitive data (e.g., emails, password hashes). This is used for phishing or larger attacks. For instance, by enumerating user IDs (incrementing from 1), a database dump can be performed. This is possible if access controls are insufficient, anonymous queries are allowed, or an IDOR vulnerability exists. You can review the previously disclosed CVE-2021-4191 in GitLab related to this.

Attack Vectors

ayrac.png

Authorization and Authentication

GraphQL APIs require more fine-grained data access control compared to REST APIs. Misconfigured authorization can lead to users accessing data beyond their permissions. For example, you can try to access users with the query I mentioned earlier.

query {
  user(id: "123") {
    id
    username
    email
  }
}

This vector is a prime opportunity for privilege escalation for an attacker. Due to GraphQL's flexibility, applying control to specific fields becomes difficult, allowing an attacker to access data outside their authorization, such as admin emails. This problem arises if field-level authorization is missing or token validation is insufficient, especially in systems not using global authentication. A similar situation occurred with GraphQL endpoints in CVE-2025-31481, where the Relay node type was used to bypass controls, leading to unauthorized queries.

Batch Querying and Denial of Service (DoS) Attacks

GraphQL allows multiple queries to be made in a single request. This feature can be used by attackers to overload the server. In other words, you can force the server to return more data.

query {
  nestedField1 {
    nestedField2 {
      nestedField3 {
        nestedField4 {
          ...
        }
      }
    }
  }
}

This type of query can strain the server's processing capacity, leading to a denial-of-service attack. From an attacker's perspective, batch querying is an easy way to exhaust resources; by combining multiple queries in a single request, it consumes CPU or RAM, slowing down and crashing the server. It is frequently used to take competitor sites offline or for ransom demands. If query batching is not limited, or if there is no rate limiting or complexity limit, these attacks are inevitable. CVE-2024-39895 in Directus is an example of a similar DoS through field duplication.

Mass Assignment Attacks

GraphQL APIs allow clients to define the data structure. We usually use mutation commands to do this. This way, we can add data to unauthorized fields.

mutation {
 updateUser(id: "2", input: {role: "admin"}) {
  id
  name
  role
 }
}

Ekran görüntüsü 2025-09-10 074725.png

This query can cause a user to be unauthorizedly promoted to an admin role. For an attacker, mass assignment is the key to data manipulation; they alter unauthorized properties by filling inputs in mutations. Such vulnerabilities appear if input validation is lacking or if blacklisting is used instead of whitelisting. CVE-2025-53364 in Parse Server leads to similar manipulations in schema loading.

Injection Attacks

GraphQL queries can translate directly into database operations. This can leave them open to classic attacks like SQL injection.

{
  userByUsername(username: "" OR 1=1 --") {
    id
    name
    email
  }
}

Ekran görüntüsü 2025-09-10 074949.png

Injection is an attacker's tool to take over the database by injecting code; if inputs are not sanitized, SQL/NoSQL commands can be inserted to dump all data. These problems arise if argument sanitization is missing or if an ORM is not used. CVE-2025-27407 in GraphQL-Ruby is an example of similar injections through untrusted schema loading.

"Deep Query" Attacks

A deep query attack involves a malicious user sending deeply nested relational queries to overload the server.

{
  userWithFriends(id: "1") {
    name
    friends {
      name
      friends {
        name
        friends {
          name
          friends {
            name
          }
        }
      }
    }
  }
}

Ekran görüntüsü 2025-09-10 075121.png

A deep query is an attacker's tactic to lock up the server with recursive queries; it multiplies the database load by deepening relationships. It's inevitable if there is no query depth limit or if recursive relationships are unlimited. CVE-2025-32031 in Apollo Gateway leads to expensive queries with deeply nested fragments.

Over-fetching Attacks

One of GraphQL's biggest advantages is that clients can get exactly the data they need. However, this flexibility can be abused.

{
  users {
    id
    name
    email
    role
    friends {
      id
      name
      email
      friends {
        name
        email
      }
    }
  }
  blogs {
    id
    title
    content
    author {
      id
      name
      email
      role
    }
  }
}

This query can consume server resources by fetching too much information about a single user. Over-fetching attacks can lead to denial-of-service (DoS) attacks. For an attacker, over-fetching is a way to exhaust resources by pulling too much data, stressing the server and causing a DoS or a data leak. These attacks become easy if there is no complexity limit or field cost calculation. CVE-2025-32031 in Apollo Gateway opens the door to similar over-fetching with deep queries.

Stored XSS

This vulnerability occurs when commands are permanently stored on the target server and later presented to the user as a web page. For example, unsanitized inputs stored on the server using a GraphQL mutation and later sent to the user can lead to stored XSS attacks.

mutation {
  createBlog(input: {
    title: "Test Blog"
    content: "<script>alert('XSS Vulnerability!')</script>"
    authorId: "1"
  }) {
    id
    title
    content
  }
}

Ekran görüntüsü 2025-09-10 075418.png

Stored XSS involves an attacker injecting a script via a mutation for permanent injection; the stored code is served to other users and is used for cookie theft or session hijacking. It occurs if input sanitization is missing or if mutations store input directly. CVE-2021-41248 in the Altair GraphQL client is an example of a similar stored XSS.

OS Command Injection

This can occur when a mutation or query uses user inputs in a system command. For example, if the server includes user inputs in shell commands (like wget, cURL, etc.) to fetch an avatar from a URL, command injection can occur due to insufficient validation or sanitization.

Ekran görüntüsü 2025-09-10 080237.png

OS command injection is a chance for an attacker to execute system commands with inputs; they can inject commands like rm -rf and take over the server. It happens if inputs are passed directly to the shell and there is no escaping. CVE-2021-23326 in @graphql-tools/git-loader leads to command injection.

Server-Side Request Forgery (SSRF)

This can occur when an attacker submits a malicious GraphQL query or mutation, sending a URL as a variable or argument. This can lead to unauthorized HTTP requests being made to a vulnerable server or system. For an attacker, SSRF is a tool to scan the internal network; they force the server to access internal resources with a URL argument, used for stealing cloud metadata or port scanning. It occurs if URLs are not validated, there is no whitelist, especially in external fetch mutations. CVE-2023-23685 in WP-GraphQL allows authenticated users to perform SSRF.

Ekran görüntüsü 2025-09-10 080353.png

ayrac.png

Throughout this article, we've seen how the flexibility offered by GraphQL can lead to serious security risks if not handled with care. We examined many attack vectors, from introspection to DoS attacks, from authorization bypass attempts to injections.

GraphQL is a very powerful tool when configured correctly. However, it's crucial to remember that every query, every mutation, can potentially open a door to a vulnerability. You can use the techniques in this article as a starting point for your own tests. Happy, secure coding.




OTHER LANGUAGES