HIGH graphql introspectiondjangobearer tokens

Graphql Introspection in Django with Bearer Tokens

Graphql Introspection in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability

GraphQL introspection in Django, when combined with bearer token authentication, can unintentionally expose the full schema and internal types even when bearer protection is present. This occurs because introspection queries are typically processed before or independently of authorization checks in many GraphQL-for-Python setups, allowing an unauthenticated or partially authenticated attacker to discover types, queries, and field names that should be guarded.

In a Django GraphQL implementation, introspection is often enabled in development and sometimes left enabled in production behind an API gateway or middleware that validates bearer tokens at the HTTP layer. If the GraphQL view does not explicitly disable introspection or enforce authorization within the resolver layer, an attacker can send an introspection query with a valid bearer token (or sometimes without one) and retrieve the complete schema. This information can reveal sensitive data models, query patterns, and potential injection surfaces, aiding further attacks such as BOLA/IDOR or injection.

When bearer tokens are used, the expectation is that only clients with a valid token can proceed. However, if introspection is not explicitly disabled, the token may grant broad visibility into the API structure. For example, a token issued for a limited scope might still allow introspection, exposing fields that should be restricted to certain roles. Attackers can leverage this to map the API surface and identify endpoints or mutations that accept user input, which can then be tested for injection or authorization flaws.

Consider a typical Django GraphQL view using graphene-django or strawberry:

from django.http import HttpRequest
from graphene_django.views import GraphQLView

class BearerGraphQLView(GraphQLView):
    def get_response(self, request: HttpRequest, data):
        # Insecure: introspection allowed regardless of token validity or scope
        return super().get_response(request, data)

In this pattern, if the view does not validate the token before allowing introspection, an attacker with any valid bearer token can retrieve the schema. Even with token validation at the middleware level, if introspection is not explicitly blocked, the schema is exposed.

To align with the checks performed by middleBrick, this scenario is flagged under the Authentication and Property Authorization categories. The scanner tests whether introspection can be executed with different token states and whether the schema is leaked, mapping findings to relevant compliance frameworks such as OWASP API Top 10 and SOC2.

Bearer Tokens-Specific Remediation in Django — concrete code fixes

To secure GraphQL introspection in Django when using bearer tokens, explicitly disable introspection in production and enforce authorization within the GraphQL layer. This ensures that even with a valid token, introspection is not available unless explicitly permitted for trusted clients.

One approach is to override the introspection field in your schema and gate it behind role or scope checks. Below is a strawberry example that disables introspection by default and allows it only for an internal monitoring token:

import strawberry
from typing import Optional

# Example: allow introspection only for a special internal token
INTROSPECTION_TOKEN = "internal-monitoring-token-123"

@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"

@strawberry.type
class Mutation:
    @strawberry.mutation
    def set_value(self, value: str) -> bool:
        return True

@strawberry.schema
class MySchema:
    query: Query
    mutation: Mutation

    # Override introspection to enforce custom logic
    @property
    def __type_map__(self):
        # In production, remove or restrict introspection entries
        if not self._introspection_allowed():
            return {}
        return super().__type_map__

    def _introspection_allowed(self) -> bool:
        # In real usage, inspect request context; here we simulate with env/headers
        import os
        return os.environ.get("ALLOW_INTROSPECTION") == "true"

In a graphene-django project, you can disable introspection at the view level by customizing the GraphQL view:

from django.http import HttpRequest
from graphene_django.views import GraphQLView

class SecureGraphQLView(GraphQLView):
    def get_response(self, request: HttpRequest, data):
        # Extract bearer token from Authorization header
        auth = request.META.get("HTTP_AUTHORIZATION", "")
        token = None
        if auth and auth.startswith("Bearer "):
            token = auth.split(" ", 1)[1]
        # Allow introspection only for a known internal token
        if data and data.get("query", "").strip().startswith("__schema"):
            if token != "internal-monitoring-token-123":
                return {"errors": [{"message": "Introspection not allowed"}]}
        return super().get_response(request, data)

Additionally, ensure that bearer token validation occurs before the GraphQL resolver chain. Use Django middleware to attach user context and enforce scope-based checks so that even if introspection is allowed in limited cases, the fields returned respect token scopes.

For operational monitoring, the middleBrick CLI can be used to verify that introspection is properly restricted:

middlebrick scan https://api.example.com/graphql

Using the GitHub Action, you can fail builds if the risk score exceeds your threshold, preventing schema exposure in deployment pipelines. The MCP server integration allows you to scan APIs directly from your AI coding assistant while developing these fixes.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Can a valid bearer token still expose the GraphQL schema via introspection?
Yes, if introspection is not explicitly disabled in the GraphQL layer, a valid bearer token can still retrieve the full schema. Always disable or tightly restrict introspection and validate token scope within resolvers.
How can I test if my Django GraphQL endpoint leaks schema through introspection?
Send an introspection query to the endpoint with various bearer token states (no token, valid token, limited-scope token). Tools like middleBrick can automate this check and report whether schema exposure occurs under different token conditions.