Security Notes
  • Whoami
  • Pentesting
    • WEP-Pen
      • Reconnaissance
      • Enumeration
      • OWSAP TOP 10
        • Injection
          • Cross Site Scripting
            • Cross Site Scripting
            • Exploitation
            • Protections
          • SQL Injection
            • SQL Injection Overview
          • NoSQL Injection
          • CRLF Injection
          • XML Injection
        • Broken Access Control
          • Path Traversal
          • Sensitive Cookie with Improper SameSite Attribute
          • Link Following
          • Incorrect Default Permissions
          • Information disclosure
          • CSRF
            • csrf checklist
          • 403 bypass
          • Exposure of WSDL File Containing Sensitive Information
          • bussiness logic checklist
          • 2FA bypass checklist
          • admin panal checklist
          • idor checklist
          • Authentication checklist
          • reset_password_checklist
          • ATO
        • Cryptographic Failures
          • Cryptographic Failure
          • Weak Encoding for Password
          • Improper Following of a Certificate's Chain of Trust
            • Understanding Digital Certificates : Self-Signed and CA-Signed Certificate **
            • Transport Layer Security (TLS) and SSL **
          • Clear Text Transmission Of Sensitive Data
            • SSLStripping **
        • Insecure Design
        • Security Misconfiguration
          • CORS Miscofigration
          • Mail Server Misconfiguration
        • Vulnerable and Outdated Components
          • Using Components with Known Vulnerabilities
        • Identification and Authentication Failures
          • JWT Hacking
          • SAML Authentication bypass
        • Software and Data Integrity Failures
          • mass assignment
          • PostMessage Vulnerabilities
            • PostMessage Vulnerabilities
            • Blocking main page to steal postmessage
            • Bypassing SOP with Iframes - part 1
            • Bypassing SOP with Iframes - part 2
            • Steal postmessage modifying iframe location
        • Security Logging and Monitoring Failures
        • Server-Side Request Forgery (SSRF)
          • SSRF
      • Checklists
        • aem misconfiguration
        • exif_geo
        • xss
        • Session Management
        • Authorization
        • cookie
        • Django
        • Symfony
        • json
        • bypass rate limit
        • Rce
        • Register Page
      • eWPTXv2 Preparation
        • Encoding & Filtering
        • Evasion Basics
        • Cross-site scripting (XSS)
        • XSS Filter Evasion
        • Cross-site request forgery (CSRF
        • HTML5
      • API-Pen
        • API Discovry
        • Reverse Engineering API Documentation
        • Excessive Data Exposure
        • Vulnerability Scanning
        • API Authentication Attacks
          • Classic Authentication Attacks
          • API Token Attacks
        • API Authorization Attacks
          • Broken Object Level Authorization (BOLA)
          • Broken Function Level Authorization
        • Improper Assets Management
        • Mass Assignment
        • SSRF
        • Injection Attacks in API
        • Evasive Maneuvers
        • GraphQL Vulnerabilities
    • NET-Pen
      • Active Directory Pentesting
        • Active Directory Components
        • Initial Attack Vectors
          • LLMNR Poisoning
          • SMB Relay Attacks
          • IPv6 Attacks ( IPv6 DNS Takeover )
          • Printer Hacking
          • Methodology
          • Some Other Attacks
            • Zerologon (CVE-2020-1472)
            • PrintNightmare (CVE-2021-1675)
        • Post-Compromise Attacks
          • Pass Attacks
          • Kerberoasting Attack
          • Token Impersonation Attack
          • LNK File Attack
          • GPP / cPassword Attacks
          • Mimikatz
          • Methodology
        • We've Compromised the Domain
          • Dumping the NTDS.dit
          • Golden Ticket Attacks
          • Methodology
        • Case Study
        • Password Attacks
      • Attack Vectors by Port
        • FTP 21
        • SSH 22
        • Telnet 23 - 2323
        • SMTP 25
        • DNS 53
        • Kerberos 88
        • POP 110-995
        • RPC 111
        • Ident 113
        • NNTP 119
        • NetBIOS 137-138
        • SMB / Samba 135-139, 445
        • MSRPC 135
        • SNMP 161
        • LDAP 389,636
        • Modbus 502
        • OpenSSL 1337
        • Ms-SQL 1433
        • Oracle Listener 1521 1522 1529
        • NFS 2049
        • MySql 3306
        • RDP 3389
        • ADB Android Debug Bridge 5555
        • WinRM 5985 5986
        • VNC 5800 5900
        • Redis 6379
        • Unreal IRC 6667
        • Tomcat 8080
        • MongoDB 27017
        • http 80
      • Network basics
      • Information Gathering
      • Privilege Escalation
        • Windows Privilege Escalation
        • Linux Privilege Escalation
    • write-ups
      • How i found a Privilege Escalation via Impersonation Features feature
      • How I was able to discover ATO Via IDOR vulnerability
      • Easy full Account Takeover via Facebook OAuth Misconfiguration
Powered by GitBook
On this page
  • GraphQL overview
  • Security issues
  • Abuse GraphQL engine
  • Broken access control
  • References
  1. Pentesting
  2. WEP-Pen
  3. API-Pen

GraphQL Vulnerabilities

PreviousEvasive ManeuversNextNET-Pen

Last updated 6 months ago

GraphQL overview

is a query language designed to build client applications by providing an intuitive and flexible syntax and system for describing their data requirements and interactions. GraphQL uses a declarative approach to fetching data, clients can specify exactly what data they need from the API. As a result, GraphQL provides a single endpoint, which allows clients to get the necessary data, instead of multiple endpoints in the case of a REST API.

GraphQL schema

GraphQL server uses a schema to describe the shape of available data. This schema defines a hierarchy of types with fields that are populated from back-end data stores. The schema also specifies exactly which queries and mutations are available for clients to execute.

Most of the schema types have one or more fields. Each field returns data of the type specified. Every type definition in a GraphQL schema belongs to one of the following categories:

  • , this includes the three special root operation types:

Scalar types

Scalar types always resolve to concrete data. GraphQL provides the following default scalar types:

  • Int a signed 32‐bit integer

  • Float a signed double-precision floating-point value

  • String a UTF‐8 character sequence

  • Boolean true or false

  • ID (serialized as a String) a unique identifier that's often used to refetch an object or as the key for a cache. Although it's serialized as a String, an ID is not intended to be human‐readable.

Object types

Most of the types in a GraphQL schema are object types. An object type contains a collection of fields, each of which has its own type. Two object types can include each other as fields.

Query types

The Query type is a special object type that defines all of the top-level entry points for queries that clients execute against a server. Each field of the Query type defines the name and return type of a different entry point.

You can use the Query type to fetch data about users as follows:

/**
 * Requests names of all users
 * You also can request another field, e. g. id or email
 */
query {
  allUsers {
    name
  }
}

/**
 * Requests a name of a user with id 1337
 * You also can request another field, e. g. id or email
 */
query {
  allUsers(id: 1337) {
    name
  }
}

All fields within the Query operation are requested parallelly.

/**
 * getUserById and getUserByName will be requested parallelly
 */
query {
  getUserById { ... }
  getUserByName { ... }
}

Mutation types

The Mutation type is similar in structure and purpose to the Query type. Whereas the Query type defines entry points for read operations, the Mutation type defines entry points for write operations. This type is optional. Each field of the Mutation type defines the signature and return type of a different entry point.

You can use the Mutation type to create a new user as follows:

/**
 * Create new user
 * Requests id, name and email fields in a response
 */
mutation {
  createUser(name:"User", email: "user@website.com") {
    id
    name
    email
  }
}

Fields within the Mutation operation are requested sequentially.

/**
 * The operations are invoked in the following sequence:
 *   1. createUser
 *   2. removeLastUser
 */
mutation {
  createUser { ... }
  removeLastUser { ... }
}

Subscription types

The Subscription type is used for notifying users of any changes, which have occured in a system. This type is optional.

The Subscription type works the following way:

  • A client subscribes on some action and creates a connection with the server (commonly via WebSocket).

  • When this action is occured the server sends a notification via the created connection.

You can subscribe to create a new user as follows:

/**
 * When a new user will be created
 * The server sends the name and email of the new user to a client
 */
subscription {
  newUser {
    name
    email
  }
}

Input types

Input types are special object types that allow you to provide hierarchical data as arguments to fields (as opposed to providing only flat scalar arguments). Each field of an input type can be only a scalar, an enum, or another input type.

Enum types

The Enum is similar to a scalar type, but its legal values are defined in the schema. Enums are most useful in situations where the user must pick from a prescribed list of options.

Union types

The Union type declares which object types are included in the union. A field can have a union (or a list of that union) as its return type. In this case, it can return any object type that's included in the union.

All of a union's included types must be object types (not scalars, input types, etc.).

Interface types

An interface specifies a set of fields that multiple object types can include. If an object type implements an interface, it must include all of that interface's fields.

A field can have an interface (or a list of that interface) as its return type. In this case, it can return any object type that implements that interface.

Introspection schema

GraphQL defines the introspection schema, which is used to ask a GraphQL for information about what queries it supports. You can fetch introspection schema with the following query:

How to read an introspection schema?

Typically, an introspection schema looks as the following one:

{
  "data": {
    "__schema": {
      "queryType": {
        "name": "Query"
      },
      "mutationType": {
        "name": "Mutation"
      },
      "subscriptionType": {
        "name": "Subscription"
      },
      "types": [ ... ],
      "directives": [ ... ]
    }
  }
}
  • The queryType, mutationType, subscriptionType define the names of fields that contain list of corresponding queries supported by an application. In other words, if the queryType name is QueryRoot you can find all supported the Query types inside the element of the data.__schema.types list with QueryRoot name.

  • The types contains all supported variables and queries.

For example, the following schema defines the User object and the allUsers query that returns the list of Users:

{
  "data": {
    "__schema": {
      "queryType": {
        "name": "QueryRoot"
      },
      "types": [
        {
          "name": "User",
          "kind": "OBJECT",
          "fields": [
            {
              "name": "name",
              "type": {
                "name": "String",
                "kind": "SCALAR"
              }
            }
          ]
        },
        {
          "name": "QueryRoot",
          "kind": "OBJECT",
          "fields": [
            {
              "name": "allUsers",
              "description": "Returns all users.",
              "args": [],
              "type": {
                "name": null,
                "kind": "LIST",
                "ofType": {
                  "name": "User",
                  "kind": "OBJECT",
                  "ofType": null
                }
              }
            }
          ]
        }
      ]
    }
  }
}

Security issues

Abuse GraphQL as an API gateway

GraphQL resolvers can be implemented as a REST API gateway and use the provided parameters to craft and send requests to the API. It the parameters are not validated properly resolvers can be vulnerable to SSRF.

Suppose, the GrapghQL scheme contains a query that provide information about an user by ID:

type Query {
    userByID(id: ID!):User
}

type User {
    id: ID!
    name: String!
    friends: [User!]!
}

The resolver can look like this (pseudocode):

results = client.get('https://api.website.internal/users/{id}')
return result.data

In this case, you can send request with the following queries:

{
    firstFriend: userByID(id: "1337/friends/1"){
        id
        name
    }
    secondFriend: userByID(id: "1337/friends/2"){
        id
        name
    }
}

This results in the following GET requests:

https://api.website.internal/users/1337/friends/1
https://api.website.internal/users/1337/friends/2

Abuse GraphQL engine

GraphQL engines are used to implement GraphQL API. The engines can have vulnerabilities or be misconfigured.

Broken access control

GraphQL does not define any access control by design. Developers implement an access contol inside resolve-methods and a business logic code. So try to bypass access control checks with the techniques used in the case of the REST API.

References:

Bypass of CSRF protection

Try to change the Content-Type header to get CSRF:

POST /api/graphql HTTP/1.1
Content-Type: application/json

{"query":"mutation ..."}
POST /api/graphql HTTP/1.1
Content-Type: application/x-www-form-urlencoded

query=mutation...

Change HTTP method

Try to send GET requests instead of POST ones to get CSRF.

References:

Bypass of rate limits

The GraphQL specification allows multiple requests to be sent in a single request by batching them together. If the developers did not implement some mechanism to prevent the sending of batch requests, you could potentially bypass the rate limit by sending queries in a single request.

mutation { login(input: { user:"a", password:"password" }) { success } }
mutation { login(input: { user:"b", password:"password" }) { success } }
....
mutation { login(input: { user:"z", password:"password" }) { success } }

Denial of service

By default GraphQL does not restrict length of queries. The GraphQL queries can be nested one inside the other and create cascading requests to the database. As a result, nested queries can be performed in order to cause a denial of service attack:

query {
  posts {
    title
    comments {
      comment
      user {
        comments {
          user {
            comments {
              comment
              user {
                comments {
                  comment
                  user {
                    comments {
                      comment
                      user {
                      ...
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Excessive errors

GraphQL injection

Even though GraphQL is strongly typed, SQL, NoSQL and Command injections are still possible since GraphQL is just a layer between a client and backend.

mutation { 
    login(input: {
        user: "admin", 
        password: "password' or 1=1 -- -"
    }) { 
        success
    } 
}

mutation {
    users(search: "{password: { $regex: \".*\"}, name:Admin }") {
        id
        name
        password
    }
}

Information disclosure

Often the GraphQL API is exposed a lot of information, such private data, debug information, hidden data or stacktraces.

References:

References

These primitive types cover the majority of use cases. However, it is possible to create .

You can also use various GraphQL IDEs or for introspection.

However, developers can forbid introspection of their applications. In this case, you can try to obtain the schema with the .

The directives contains a list of supported .

This is possible since the ID Scalar should be and "1337/friends/1" is a valid string.

In order to determine which engine is used you can use the .

Tool: +

Change Content-Type by

GraphQL has a . However, error messages can be too informative. Try to cause errors, for instance by fuzzing parameters, error messages can reveal details about the error, actual paths on the system, chunks of code or queries, etc.

custom scalar types
GraphQL Voyager
clairvoyance
directives
serialized as a string
graphw00f
Report: Confidential data of users and limited metadata of programs and reports accessible via GraphQL
Report: Insufficient Type Check leading to Developer ability to delete Project, Repository, Group, ...
Report: Insufficient Type Check on GraphQL leading to Maintainer delete repository
AutoGraphQL
How to use guide
@inhibitor181
Report: CSRF on /api/graphql allows executing mutations through GET requests
nice and expressive way of returning errors
Team object in GraphQL disclosed total number of whitelisted hackers
Team object exposes amount of participants in a private program to non-invited users
GraphQL Specification
Practical GraphQL attack vectors
Public GraphQL APIs
Apollo Docs: GraphQL schema basics
GraphQL
Scalar
Object
Query
Mutation
Subscription
Input
Enum
Union
Interface