Graphql Introspection in Django with Basic Auth
Graphql Introspection in Django with Basic Auth — how this specific combination creates or exposes the vulnerability
GraphQL introspection allows clients to query the schema for types, queries, and mutations. When a Django GraphQL endpoint is exposed with Basic Authentication but introspection is not explicitly disabled, unauthenticated or partially authenticated attackers can use introspection queries to map the API surface. middleBrick’s Authentication and BOLA/IDOR checks flag this as a risk because the presence of Basic Auth does not inherently limit introspection if views or GraphQL routers do not enforce stricter controls.
In Django, GraphQL is commonly served via packages such as graphene-django or Strawberry. If the GraphQL view is mounted at a path like /graphql/ and Basic Auth is applied at the web server (e.g., via HTTPBasicAuth in Apache/Nginx) or at the Django view level, an attacker with network access or partial credentials may still send an introspection query. Successful introspection reveals which types, queries, and mutations exist, which in turn aids in crafting further attacks such as IDOR or BFLA. middleBrick’s GraphQL-related checks correlate introspection exposure with authentication mechanisms and flag scenarios where introspection is reachable under Basic Auth without additional schema-level restrictions.
Consider a typical Django GraphQL view using graphene:
from django.http import HttpRequest
from graphene_django.views import GraphQLView
class BasicAuthGraphQLView(GraphQLView):
def get_response(self, request: HttpRequest, data):
# Weak: only checks a static token, not per-user credentials
auth = request.META.get('HTTP_AUTHORIZATION', '')
if not auth.startswith('Basic '):
return {'errors': [{'message': 'Unauthorized'}]}
return super().get_response(request, data)
If this view is deployed without schema-level introspection disabling, an attacker can POST an introspection query to the endpoint and enumerate the schema even when Basic Auth is present but not tied to a restrictive permission model. middleBrick’s Property Authorization and Input Validation checks help identify whether introspection is guarded by proper authorization logic.
Additionally, when using Django with an OpenAPI/Swagger spec that describes a GraphQL endpoint, the spec may inadvertently document the GraphQL route as a standard HTTP endpoint. middleBrick’s OpenAPI/Swagger analysis resolves $ref paths and cross-references runtime findings, highlighting mismatches where introspection is reachable despite documented authentication requirements.
Basic Auth-Specific Remediation in Django — concrete code fixes
To secure a GraphQL endpoint in Django when using Basic Authentication, you should combine transport-level authentication with schema-level controls. Disable introspection in production and ensure that any Basic Auth wrapper validates credentials properly and does not rely on static tokens or missing checks.
1) Disable GraphQL introspection in production builds. With graphene-django, set graphql_schema with introspection disabled:
from graphene import Schema
from graphene_django.models import DjangoObjectType
from django.conf import settings
schema = Schema(
query=MyQuery,
mutation=MyMutation,
enable_introspection=settings.DEBUG # False in production
)
With Strawberry, use strawberry.Schema and omit the enable_introspection flag or explicitly set it to False in production:
import strawberry
from django.conf import settings
@strawberry.type
class Query:
hello: str = "world"
schema = strawberry.Schema(
query=Query,
enable_introspection=settings.DEBUG
)
2) Implement robust Basic Auth at the view or middleware level, validating credentials per request rather than using a static token. Example using Django REST Framework’s HTTPBasicAuthentication combined with a custom permission:
from rest_framework.authentication import HTTPBasicAuthentication
from rest_framework.permissions import BasePermission, SAFE_METHODS
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class HasValidBasicAuth(BasePermission):
def has_permission(self, request, view):
auth = request.META.get('HTTP_AUTHORIZATION', '')
if not auth.startswith('Basic '):
return False
# Validate credentials against Django user model or a secret store
# Example: decode and check against environment variables
import base64
encoded = auth.split(' ')[1]
decoded = base64.b64decode(encoded).decode('utf-8')
username, password = decoded.split(':', 1)
# Replace with secure credential check (e.g., secrets manager or Django user)
valid = (username == 'apiuser' and password == 'strongpassword')
return valid
class SecureGraphQLView(APIView):
authentication_classes = [HTTPBasicAuthentication]
permission_classes = [HasValidBasicAuth]
def post(self, request):
# Your GraphQL handling logic here
return Response({'data': 'ok'})
3) If you rely on web server Basic Auth (e.g., Nginx), ensure the GraphQL path is not unintentionally exposed. Use location-level restrictions and validate that introspection is disabled at the application level, as server-level auth may still allow introspection if misconfigured.
middleBrick’s CLI can be used in scripts to verify that introspection is disabled and that authentication is required: middlebrick scan <url>. The GitHub Action can enforce a security score threshold to prevent insecure configurations from reaching production, while the MCP Server allows you to scan APIs directly from your AI coding assistant during development.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |