It seems like developers working on REST APIs have finally come to terms with the dangers of verbose error messages, but GraphQL developers are still learning what happens when their API schema is left unprotected.
In March 2022, CVE-2021-4191 disclosed how GitLab’s API allowed “a remote, unauthenticated attacker to recover usernames, names, and sometimes email addresses”. This was possible since the User object type was exposed without any sort of authentication.
Of course, auth-related vulnerabilities are commonly reported on other APIs, but detecting them in GraphQL can be aided by a singular feature of the language: Introspection.
Introspection is a handy development feature that, when enabled in production, discloses the types and operations that are supported by the API, including (sometimes) queries and mutations that are only available to high privilege users.
Successful introspection query on the Damn Vulnerable GraphQL Application (DVGA) API
Most popular GraphQL servers now disable this feature in production by default, which is a step in the right direction, but clearly not enough.
Visualization of the DVGA API mutations by importing its schema in GraphQL Voyager
Companies often rely on this feature to help others navigate their public APIs, as described in a HackerOne report submitted to New Relic:
“We do not consider introspection revealing schema definitions to be sensitive information exposure. Our scheme definitions themselves are not sensitive information and we have designed our endpoints to be discoverable via introspection. Introspection is not something limited to internal use, quite the opposite; it’s super useful for external implementers to know how our API/domain works.”
Even if Introspection is disabled, an attacker can obtain data by abusing the “Schema Suggestions” feature.
If you’re not familiar with this feature, it’s basically a way for some GraphQL servers to help developers build queries by hinting at the correct name of operations, types, and fields.
Below, we can see an example: when we try to fetch the “descriptions” field (which doesn’t exist) using the Introspection query, the server tries to help us fix this mistake by responding with “Did you mean ‘description’?”
Query field name suggestion on the DVGA API
Nikita Stupin’s research and its resulting tool clairvoyance make this feature a whole lot easier to exploit … all you need is a wordlist, and the tool will brute-force its way to the original API schema, based on the server’s helpful hints.
Apollo GraphQL is one of the servers that offer suggestions “out of the box” and, unfortunately, there is currently no way to disable them, but there are some workarounds.
Well, attackers looking to bypass business logic limitations would also love the fact that the GraphQL schema specifies which fields are deprecated, and there are even some verbose “deprecation reasons” that disclose internal decisions and future iterations of the API.
Deprecated fields in the DVGA schema
Often knowing about a sensitive operation is half the battle … when you combine this with other vulnerabilities, exploiting GraphQL APIs is as easy as pie.
IDOR (Insecure Direct Object Reference), CSRF (Cross-Site Request Forgery), SQL Injection, and all types of Broken Access Control vulnerabilities paired with GraphQL are easier to detect and exploit, even though they occur with the same frequency in REST APIs.
And we shouldn’t forget about the vulnerabilities that are more likely to occur due to the inherent flexibility of this querying language, such as Denial of Service (DoS).
GraphQL clients can specify exactly what (and how much) data they want to receive from the server, so it’s easy to imagine how this flexibility might be a powerful tool when trying to overload a system with requests:
Abusing batch requests using the DVGA
Current best practices suggest a combination of the following approaches:
- Limiting the depth of a query (see graphql-depth-limit)
- Limiting the allowed cost of a query using cost estimates (see graphql-validation-complexity and graphql-cost-analysis)
- Limiting the number of objects that can be fetched by setting a pagination maximum
GraphQL developers in effect need to work against the features of the language to ensure that their APIs are as robust, opaque, and reliable as any other.
Luckily, there is an ecosystem of open-source security tools that can help, among them:
- batchQL, a script that attempts common attacks against GraphQL APIs “with a focus on performing batch GraphQL queries and mutations”;
- the InQL Burp extension, which automatically tries to find GraphQL endpoints and development consoles;
- graphql-path-enum, which helps find circular references in the schema, that may lead to DoS
… and many more.