Demystifying GraphQL Security: A Comprehensive Guide to Introspection

Demystifying GraphQL Security: A Comprehensive Guide to Introspection

Whether or not to disable introspection has been a common debate among GraphQL developers since its inception. In this blog post, we will explain why completely disabling introspection is not necessary and why it can be counterproductive.

Marc-André Giroux, Author of Production Ready GraphQL

Why is introspection useful?

What is introspection?

Firstly, it's essential to understand what Introspection is in GraphQL. It is the ability to provide metadata about its schema, including types, fields, and directives. It allows developers to explore the API structure and understand the available data.

The simplest way to know if your introspection is open is to fetch it yourself!

curl --location 'https://example.com/graphql' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{"query":"query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } 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 ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } }","variables":{}}' \
> introspection.json
The curl introspection command

An essential feature for productivity and flexibility

Introspection is a handy feature for front-end and client developers. In particular, one of the most significant advantages of GraphQL is its ability to allow them to request only the data they need. Introspection plays a crucial role in this process by enabling them to discover and understand the available types and fields in the schema. By disabling introspection, you're essentially taking away a valuable tool that developers can use to improve their productivity and make better-informed decisions about how to structure their queries.

Moreover, Introspection can be a valuable tool for API documentation and discovery. By disabling it in production, you might need to invest additional resources in maintaining separate documentation and keeping it up-to-date. This can increase the complexity of your API maintenance process and potentially lead to inconsistencies between the actual schema and the documentation.

Is introspection really a security concern?

It seems like a potential security risk

The main argument for disabling introspection is that it can be a security risk. By allowing introspection, malicious actors can exploit this information to craft targeted attacks against your application. In particular, it can potentially expose additional entry points, such as hidden or undocumented operations that might not be as secure as the rest of your application.

It can also be a performance issue. When a GraphQL server receives an introspection query, it must traverse the entire schema and gather metadata, which can be time-consuming and resource-intensive.

Where there's a will; there's a way

At that point, it might seem obvious to disable introspection for security purposes. The problem is that disabling it is just a "false good idea". There is always a simple way to find your schema and craft malicious requests against your GraphQL API.

Field suggestion leaks your schema

Most GraphQL engines have a feature called Field Suggestion. When the server receives a query with invalid fields, it will respond with an error message indicating that the requested field does not exist.

However, this error message also contains information about fields with similar names that do exist within the schema. This GraphQL feature is called Field Suggestion.

{
  "errors": [
    {
      "message": "Cannot query field \"space\" on type \"Query\". Did you mean \"escape\"?",
      "locations": [
        {
          "line": 1,
          "column": 5
        }
      ],
      "extensions": {
        "code": "GRAPHQL-VALIDATION-FAILED"
      }
    }
  ]
}
Field suggestion in GraphQL

This feature can be abused: by sending random field names in a query and gathering the suggestions that the servers send back, one can build back the complete GraphQL Schema! This is an attack called Field Fuzzing.

Clairvoyance is an open-source tool created by Nikita Stupin and maintained by Escape that allows developers to retrieve GraphQL introspection data even when disabled using Field Fuzzing.

By analyzing these error messages, Clairvoyance can determine the structure of the schema and retrieve the necessary introspection data.

Full GraphQL schema built back by Clairvoyance on an endpoint with deactivated introspection

On Apollo and Yoga servers, you can easily disable Field Suggestion using our free, open-source tool GraphQL Armor.

The frontend knows everything.

Obviously, it is possible to recreate the introspection from the traffic generated by a front-end. This means that even if you disable introspection, a determined attacker could still gain access to the schema information by navigating to your application's website.

My introspection is only enabled on staging

Do you think keeping your introspection open on staging makes your production more secure?

Most of the time, we notice that if your production endpoint is available on https://graphql.example.com/, your staging environment is accessible through https://staging.graphql.example.com/. In that case, getting the introspection of your staging is a no-brainer.

Let's say you tried to hide your staging environment on a random URL. At Escape, we developed open-source software to find any GraphQL endpoint related to your main application. Using subdomain enumeration, web crawling, and brute forcing, Goctopus can find any of your GraphQL endpoints and know whether introspection or field suggestions are enabled on each of them.

We use Goctopus in our own platform, Escape, to index all our customer's exposed GraphQL Endpoints. We discovered that a surprisingly high amount of organizations have their staging and development environment open, with introspection activated.

In our platform, Escape, we index all our customer's exposed GraphQL Endpoints using Goctopus

Conclusion: don't trade productivity against obscurity

At Escape, we believe in security by obscurity, and thus we advise not to disable introspection.

  1. You can keep your introspection enabled: Completely disabling introspection doesn't actually make your server more secure; it just makes it harder for developers to do their jobs.
  2. Optionally, implement role-based access control: If you still don't fill confident in letting your introspection open to the world, you can configure your GraphQL server to enable introspection only for specific user roles, such as administrator or developers, ensuring the feature is accessible only to trusted users.

Ultimately, deciding to disable introspection in production depends on your specific use case and requirements. Ensure you provide your developers with the best experience while maintaining a robust application.

Wanna know more about GraphQL Security?

Check out our blog posts below and learn how to build safe GraphQL APIs: