Forging GraphQL Bombs, the 2022 version of Zip Bombs
Tags: graphql, security, cybersecurity, vulnerability
Published: 2022-08-12 13:16:24

---
title: Forging GraphQL Bombs, the 2022 version of Zip Bombs
published: true
description: GraphQL Bombs are a new and widespread vulnerability exploiting file uploads on GraphQL endpoints
tags: graphql, security, cybersecurity, vulnerability
cover_image: https://blog.escape.tech/content/images/size/w2000/2022/08/--Landscape---GraphQL.Security--3-.png
canonical_url: https://blog.escape.tech/forging-graphql-bombs-the-2022-version-of-zip-bombs/
---

[Zip Bombs](https://en.wikipedia.org/wiki/Zip_bomb) are a thing of the past, but the concept behind them is still relevant nowadays. Indeed, your GraphQL application might be vulnerable to what we'll call **GraphQL Bombs** in this article. **Read on to know if you're vulnerable and how to secure your GraphQL application!**

## How do zip bombs work?

Before diving into the topic, let's take a moment to understand the concept _behind_ zip bombs.

Zip files are lossless compressed archives whose most common compression algorithm is named deflate. It works by finding repeating patterns in the data, then replacing these patterns with a much shorter token.

![Zip compression works by replacing repeating patterns with tokens.](https://blog.escape.tech/content/images/2022/07/huffman-1.svg)

Therefore, a repetitive sequence of bytes will be much shorter after compression. Creating a zip bomb consists of meticulously crafting a sequence of bytes that compress _very well_, by several orders of magnitude. Then, when the victim decompresses the zip file, **the resulting data will be much larger** than the original archive.

## Aliased queries

GraphQL is a powerful language with many not-well-known features. **One of these features is the ability to alias queries.**

Let's consider a simple blog with an `article(id: Int!)` query. If we were to fetch one article, we would do it like this:

```graphql
query {
  article(id: 1) {
    title
    author
  }
}
```

This will produce something like this:

```json
{
  "article": {
    "title": "Hello World!",
    "author": "John Doe"
  }
}
```

But GraphQL has a nice feature allowing developers to **query the same resolver several times** with a different return name:

```graphql
query {
  first:  article(id: 1) { title author }
  second: article(id: 2) { title author }
  third:  article(id: 3) { title author }
}
```

This will produce a similar result, but `article` is now aliased as `first`, `second` and `third`:

```json
{
  "first": {
    "title": "Hello World!",
    "author": "John Doe"
  },
  "second": {
    "title": "Yay, second article!",
    "author": "Jane Doe"
  },
  "third": {
    "title": "That's a lot of articles",
    "author": "Jaune D'œuf"
  }
}
```

You may already notice something there, and indeed, you can already design a first vulnerability to exploit this feature – **aliasing facilitates brute-force:**

```graphql
mutation {
  a1: login(user: "john", password: "password") { id }
  a2: login(user: "john", password: "qwerty") { id }
  a3: login(user: "john", password: "123456") { id }
  # Let's try the most common passwords!
}
```

## File uploads

The second part of **the vulnerability requires having enabled file uploads over GraphQL.**

Many [popular GraphQL engines](https://www.apollographql.com/docs/apollo-server/data/file-uploads/) support uploads in GraphQL, [some even natively](https://www.graphql-yoga.com/docs/features/file-uploads).

The [GraphQL multipart specification](https://github.com/jaydenseric/graphql-multipart-request-spec) describes how to implement file uploads in GraphQL. While usual GraphQL queries are sent as `application/json`, file uploads are sent as `multipart/form-data`. This means that the HTTP request body has _multiple parts_, and their functions, described in the specification, can be summarized as follows:

1. The **operations** part contains the GraphQL query. This is the part that is usually sent as `application/json`.
2. The **map** part helps the server to find data in the request body.
3. Any other part can be used in the operations part as long as it is correctly mapped. These parts may contain any type of data the server can handle but are usually images or binary data.

Here is what a profile picture upload looks like:

```http
POST /graphql HTTP/1.1
Connection: keep-alive
Content-Length: 78346
Content-Type: multipart/form-data; boundary=----boundaryMGv2RzA6GpOE3Hry
Host: example.com

------boundaryMGv2RzA6GpOE3Hry
Content-Disposition: form-data; name="operations"

{
  "query": "mutation ($picture: File!) {updateUserPicture(picture: $picture)}",
  "variables": { "picture": null }
}
------boundaryMGv2RzA6GpOE3Hry
Content-Disposition: form-data; name="map"

{
  "file1": ["variables.picture"]
}
------boundaryMGv2RzA6GpOE3Hry
Content-Disposition: form-data; name="file1"; filename="gautier.jpg"
Content-Type: image/jpeg

(77 kB of binary data)
------boundaryMGv2RzA6GpOE3Hry--
```

You can see here that the part having `name="file1"` is mapped to `variables.picture`, allowing the server to find the file in the request body.

GraphQL file uploads work almost the same as file uploads in REST, at least from the HTTP perspective, which means that **vulnerabilities that exist in REST can be exploited in GraphQL.** But, unfortunately, that's not all…

## GraphQL bombs

As you might have guessed, GraphQL bombs combine the two previous features introduced in the article. The concept is the following: **referencing the same file several times using aliased queries.**

Let's consider that we call `updateUserPicture(picture: File!)` one thousand times, using aliases, with all calls referencing the same 1 MB file:

```graphql
mutation {
  a1: updateUserPicture(picture: $picture)
  a2: updateUserPicture(picture: $picture)
  a3: updateUserPicture(picture: $picture)
  # ...
  a1000: updateUserPicture(picture: $picture)
}
```

![GraphQL bombs consist in referencing the same file several times.](https://blog.escape.tech/content/images/2022/07/gbomb.svg)

**This request would be less than 2 MB but would result in 1 GB of data for the server to process.**

Depending on what the server does with the data, this request may cause memory or CPU exhaustion, leading to decreased performance or even a server crash.

## Mitigation

There are several steps necessary to mitigate this vulnerability:

1. **Properly configure the server limits to file uploads.**
   - [For Apollo with graphqlUploadExpress](https://github.com/jaydenseric/graphql-upload/blob/aa15ee0eb2b3a4e2421d098393bbbf9252f1a8c7/graphqlUploadExpress.js#L29)
   - [For GraphQL Yoga](https://www.graphql-yoga.com/docs/features/file-uploads#configuring-multipart-request-processing-only-for-nodejs)
2. **Limit the usage of batching and aliasing with [GraphQL Armor](https://github.com/Escape-Technologies/graphql-armor#readme)**, an open-source project developed by Escape - GraphQL Security to address the most common GraphQL vulnerabilities.
3. If GraphQL Armor does not support your engine yet, you may also try [graphql-no-batched-queries](https://github.com/ivandotv/graphql-no-batched-queries#readme) and [graphql-no-alias](https://github.com/ivandotv/graphql-no-alias#readme).