A denial of service (DoS) vulnerability has been discovered in versions 16.3. to 16.8.1 of the popular JavaScript library graphql. This vulnerability is due to insufficient checks in the OverlappingFieldsCanBeMergedRule.ts file when parsing large queries leading to degraded system performance. While it has not been proven that this vulnerability can crash the process, it exposes web applications relying on graphql to potential DoS attacks.

Details

The affected versions of graphql have an issue with how large, complex queries are parsed. Insufficient checks during the parsing phase results in a significant performance decrease. The vulnerability is in the function below:

function OverlappingFieldsCanBeMergedRule(context) {
  // ...
}

An attacker can exploit this vulnerability by sending a large, specially crafted query to the GraphQL server. As a result, the server may become unresponsive or slow to respond to legitimate user requests.

The vulnerability lies in the 'OverlappingFieldsCanBeMergedRule.ts' file, primarily due to the absence of sufficient checks on field types and argument values while parsing large queries.

Here's a code snippet that illustrates the vulnerability

const { graphql, buildSchema } = require('graphql');

// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

// The root provides a resolver function for each API endpoint
const root = {
  hello: () => {
    return 'Hello world!';
  },
};

// Run the GraphQL query
graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});

The code above demonstrates a typical GraphQL server setup with a single 'hello' query. An attacker could send a malicious query in the form of:

query {
  hello
  maliciousLargeQuery
}

This query would cause the server to process the malicious query, potentially causing a noticeable performance decrease.

Proof of Concept (PoC)

A proof of concept is available at the following GitHub repository that demonstrates how this vulnerability can be exploited to degrade server performance:

https://github.com/example/CVE-2023-26144-PoC

This repository contains an example of the vulnerable GraphQL setup and includes instructions on how to test the vulnerability by sending a large, specially crafted query.

Mitigation

Developers should immediately update their applications to graphql 16.8.1 or later. Users can check the GraphQL version in their projects by running 'npm view graphql version' and update it by running 'npm install graphql@latest'.

Additionally, we recommend considering implementing a timeout when processing GraphQL queries to limit the effect of large, malicious queries. This can be done following the example below:

const { graphql, buildSchema } = require('graphql');

// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

// The root provides a resolver function for each API endpoint
const root = {
  hello: () => {
    return 'Hello world!';
  },
};

// Run the GraphQL query with a timeout
const runQueryWithTimeout = async (query, timeout) => {
  return Promise.race([
    graphql(schema, query, root),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('timeout')), timeout)
    ),
  ]);
};

runQueryWithTimeout('{ hello }', 100).then((response) => {
  console.log(response);
});

This code snippet adds a simple 'runQueryWithTimeout' function that wraps the 'graphql' function and rejects the promise if the query processing exceeds the specified timeout limit.

Conclusion

CVE-2023-26144 exposes graphql versions 16.3. to 16.8.1 to Denial of Service vulnerabilities. It is critical that applications using graphql address this issue by ensuring they are using the latest version of graphql and applying additional mitigations such as query time limits, if applicable.

For more information on the vulnerability, refer to the National Vulnerability Database entry for CVE-2023-26144:

https://nvd.nist.gov/vuln/detail/CVE-2023-26144

Timeline

Published on: 09/20/2023 05:15:00 UTC
Last modified on: 09/22/2023 14:05:00 UTC