A Story of GraphQL ; Tuning Out Introspection Vulnerabilities

AliBawazeEer
9 min readMar 11, 2024

--

Ever seen a one-man band at a crowded bar? Juggling instruments, stomping on pedals, singing their heart out — it’s a chaotic symphony, a testament to human multitasking (and possibly questionable musical taste). Well, GraphQL introspection queries are kind of like that one-man band. They’re designed to expose everything a GraphQL server has to offer, like a musician frantically displaying every instrument in their arsenal. While it seems helpful in the beginning, just like with the one-man band, this unrestricted access can lead to some unexpected (and potentially dangerous) consequences.

This blog will delve into the security issues associated with GraphQL introspection queries, helping you avoid the pitfalls of an oversharing server and ensuring your GraphQL API remains a harmonious melody, not a cacophony of vulnerabilities.

As i conclude my musical journey through Nashville, the “Country Music Capital of the World,” So, saddle up, grab a glass of sweet tea, and let’s get started!

TL;DR: Secure your GraphQL API

Check for specific headers in POST requests: Restrictions might apply beyond GET requests.
- Restrict access: Only authorized users should access the API.
- Disable introspection: This prevents attackers from discovering your API schema.
- Introspection leakage: If enabled, it might expose all sensitive data like PII.
- Mapping complexity: Consider using open-source frameworks for simplifying mapping to build your enumeration Queries.
- GraphQL lacks built-in authentication, leaving potential security gaps. Developers must implement authentication to prevent unauthorized access to sensitive data. Without proper authentication, anyone can potentially access exposed information through the GraphQL API.

Summary: GraphQL vs. REST APIs

GraphQL simplifies data fetching: A single request gathers all the necessary data, reducing complexity for developers.
REST often requires multiple requests: Data is scattered across various endpoints, making the process more involved.

While GraphQL boasts efficiency with its single-request approach for fetching data, unlike REST’s multiple endpoint calls, a crucial caveat exists: GraphQL isn’t inherently secure. This blog post delves into a specific security concern: Introspection vulnerabilities. We’ll explore how this vulnerability can be exploited

GraphQL offers a flexible and efficient alternative to REST APIs for data access, but requires careful security considerations.

  • — — — — — — — — -+ — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — — — — — — — -+
    | Feature | GraphQL | REST |
    + — — — — — — — — -+ — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — — — — — — — -+
    | Endpoints | Single | Multiple |
    | Queries | Structured and flexible | Precise parameters for specific endpoints |
    | Client Benefits | Unified data access | |
    | Server Benefits | Simplified data access logic | |
    | Operations | CRUD (Create, Read, Update, Delete) | CRUD |
    | Data Structure | Organized by types and fields | Endpoints |
    | Schema | Defines capabilities and limits access | None |
    | Nodes | Objects with fields (potential security risk) | |
    | Edges | Connections between objects (sometimes overlooked in security) | |
    + — — — — — — — — -+ — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — — — — — — — -+

GraphQL Organized by types and fields, not endpoints. Single endpoint provides access to all data.

CRUD operations: Queries (read) , Mutations (create, update, delete) and
Subscriptions (real-time updates)

Schema: The schema outlines the types of data available (e.g., Users, Products, Orders) and their fields (e.g., name, price, status).

This is the most important where it Defines the capabilities of the API and limits what can be accessed. Includes types (object definitions) and fields (object attributes). It acts as a documentation for the API, clearly specifying what data can be requested and manipulated.

With the basics of GraphQL schemas laid out, we can now explore the realm of exploiting GraphQL misconfiguration and its impact on security.

just like any other penetration testing activity, enumeration .. enumeration and way to start finding GraphQL endpoints ,

Directory Findings !!

using tools such gobuster or burb intruder with wordlist could help identify exposed endpoints.. some wordlists

graphiql
graphiql.css
graphiql/finland
graphiql.js
graphiql.min.css
graphiql.min.js
graphiql.php
graphql
graphql/console

Wordlist-PayloadalltheThings

for additional fingerprinting , a nice tool which can’t work in my case by default cause the server require only Post Request and couple of headers
Graphw00f — GraphQL Server Fingerprinting

in my case the moment i loaded the site a post requests was .

Ah, you’ve found a GraphQL endpoint, but what’s next? That’s where introspection comes in! It might sound fancy, but it’s actually quite simple.

Verifying the endpoint or request uses GraphQL ; in my case it simple from the name of endpoint but mostly not straight forward

Sending the Special Signal: This phrase acts as a knock on the door, a way to check for GraphQL used in the backend.

query{__typename}
from burp repeater screenshot request & response

This method alone doesn’t definitively confirm a GraphQL endpoint is vulnerable to introspection vulnerability rather a way for fingerprintng and crafting your next steps

another method for verifying endpoint is an error based

query the {__schema}

Dissecting GraphQL & Understanding introspection Vulnerability

Imagine you’re trying to use a new app. Introspection is like having a built-in instruction manual that tells you what the app can do and what information it can access.

In GraphQL, introspection terms like __Schema, __Type, and __Field allow you to explore an API’s capabilities. Think of them as tools for understanding the data types, fields, and arguments available of the whole structure with an introspection query (https://graphql.org/learn/introspection)

Here’s how it works in GraphQL:

1. Peeking under the hood:

You can send a special query to the API itself, asking it to reveal its features. This is like flipping to the “Features” section of the manual.

2. Seeing what’s available:

This query shows you all the types of data (like users, posts, products), the fields within those types (like username, title, description), and even special instructions (called directives) that can be used in your queries.

3. Unlocking further exploration:

If the API allows introspection (like having an open manual), you can use this information to understand its capabilities and build powerful queries to retrieve the data you need.
So, how do you use introspection? Here’s the basic query you can send (if the API allows it):

{__schema{types{name,fields{name}}}}

This will give you a basic overview of the types and fields available in the API. You can then use this information to dig deeper and craft more specific queries to get the data you’re looking for!

Introspection

To use introspection to discover schema information, query the __schema field. This field is available on the root type of all queries.

query={__schema{types{name,fields{name}}}}

With this query you will find the name of all the types being used:

{__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
digging deeper for each names

Enumerate Database Schema via Introspection

If introspection is enabled but the below query doesn’t run, try removing the onOperation, onFragment, and onField directives from the query structure.

query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
args {
...InputValue
}
onOperation
onFragment
onField
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}

This code is a GraphQL introspection query. It’s like a request sent to a server to explore and understand the available data and functionalities it offers through the GraphQL API. Think of it as asking the server,

What kind of data do you have?
hat operations can I perform on it?”

The query delves into several aspects of the schema, including:

Types of data: It identifies the different categories of data available, like users, products, or orders.
Fields within each type: It explores the specific elements (fields) for each data type, such as name, price, or status for a product.
Operations: It checks for supported operations like fetching data (queries), modifying data (mutations), or receiving real-time updates (subscriptions).

In essence, this query acts like a map that reveals the structure and capabilities of the GraphQL API, allowing you to understand what data it holds and how you can interact with it.

Exploring a Store’s Inventory with GraphQL

Imagine you’re working with a GraphQL API for an online store. You’ve used introspection and discovered the following:

The root query object is called products.
The products object has a field named getAllProducts that takes an optional argument called category.
Crafting a Query:

Here’s a GraphQL query to retrieve all products in the “Clothing” category:

query {
products {
getAllProducts(category: "Clothing") {
# Specify the desired product details
id
name
price
image
}
}
}
  • The query starts with query, indicating data retrieval.
  • We access the products object (products { … }).
  • Inside the products object, we use the .getAllProducts field.
  • We provide the category argument with the value “Clothing” to filter the results.
  • Within .getAllProducts, we specify specific product details we want to
  • retrieve using field names like id, name, price, and image.
    Response (Example):

The response might look like:

JSON
{
"data": {
"products": {
"getAllProducts": [
{
"id": "123",
"name": "T-Shirt",
"price": 29.99,
"image": "https://example.com/images/t-shirt.jpg"
},
{
"id": "456",
"name": "Jeans",
"price": 59.99,
"image": "https://example.com/images/jeans.jpg"
}
]
}
}
}

Time To Extract Data by constructing our query

The request we intercepted ;

{"operationName":"fetchNews","variables":{"filter":{"offset":0,"limit":20,"crNumber":null,"pageType":"PUBLIC_NEWS","isPublished":true,"language":"en"}},"query":"query fetchNews($filter: NewsFilter) {\n  getAllNewsWithoutActions(filter: $filter) {\n    news {\n      id\n      title\n      author\n      createdBy\n      description\n      publishedDate\n      cdnFilePath\n      activityName\n    }\n    totalItems\n    totalPages\n  }\n}\n"}

extracting all email in ticket systems

GraphQL Security Pitfalls: Lack of Built-in Access Control

GraphQL offers flexibility but can introduce security vulnerabilities if not implemented cautiously. Here’s a summary of the key points:

Core Issue: By design, GraphQL lacks a built-in access control system. Developers rely on writing custom “resolvers” to manage data access for each query. This can lead to vulnerabilities.

Improper Access Control (IDOR): Legitimate queries might allow unauthorized access to other users’ data by manipulating variables
Field Injection: Legitimate queries might be modified to include unauthorized fields

Conclusion

In conclusion, while talented individuals excel in their respective domains, just like full-stack developers bring unique skillsets to building applications, offensive security testing requires the specialized expertise, collaboration, and comprehensive approach offered by a professional team. This team-based approach ensures a more thorough assessment, identification, and mitigation of your organization’s security vulnerabilities, ultimately providing a more robust defense against evolving cyber threats.

NABD Solutions | Offensive Security Researchers

References

https://www.guru99.com/graphql-vs-rest-apis.html

Tools; a recommendation to play around with

--

--