Information Disclosure in Django with Bearer Tokens
Information Disclosure in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Information Disclosure occurs when an API or application unintentionally exposes data to an entity that should not have access to it. In Django, combining Bearer Token authentication with misconfigured endpoints, verbose errors, or improper transport protections can expose secrets, user data, or system internals.
Bearer tokens are typically transmitted in the Authorization header as Authorization: Bearer <token>. If a Django API does not enforce strict access controls, tokens may be leaked through logs, error messages, or insecure caching. For example, when token introspection or validation errors return detailed responses, an attacker can infer whether a token is valid or gather metadata about the authentication backend. This is especially risky when endpoints do not uniformly require authentication, allowing unauthenticated probing to reveal which routes leak information.
Django REST Framework (DRF) projects commonly use token-based authentication, and misconfigured permissions can lead to Information Disclosure. If a viewset or API endpoint lacks proper permission classes, such as IsAuthenticated or custom token validation, sensitive model instances may be returned to any caller. Consider a profile endpoint that returns user details based on a lookup parameter without verifying ownership:
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.contrib.auth.models import User
@api_view(['GET'])
def user_profile(request, username):
user = User.objects.get(username=username) # Dangerous: may expose any user
return Response({'username': user.username, 'email': user.email})
An attacker can iterate over usernames to enumerate valid accounts and email addresses, a classic Information Disclosure vector. If the endpoint also exposes stack traces in production (e.g., DEBUG=True in settings), token validation errors or database exceptions may reveal parts of the token or internal paths.
Another scenario involves OpenAPI/Swagger specs served in Django without access restrictions. If schema/ is publicly reachable and contains examples with hardcoded Bearer tokens, those tokens can be harvested. Even when using middleware to strip sensitive headers, development or staging environments might inadvertently serve specs with real tokens embedded in examples.
The LLM/AI Security checks unique to middleBrick specifically test for System Prompt Leakage and Active Prompt Injection, which do not apply here; however, Information Disclosure in API design remains a foundational risk. Scanning with middleBrick can surface these issues by correlating unauthenticated endpoints with data exposure findings, helping teams prioritize fixes before tokens leak into broader attack surfaces.
Bearer Tokens-Specific Remediation in Django — concrete code fixes
Remediation centers on ensuring Bearer tokens are never exposed in responses, logs, or error messages, and that endpoints consistently enforce authentication. Below are concrete Django code examples to mitigate Information Disclosure.
1. Enforce authentication on all sensitive endpoints
Use Django REST Framework’s permission classes to require valid tokens on every endpoint that handles sensitive data. Avoid relying on view-specific decorators alone; apply global defaults and opt-out only where necessary.
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class SecureProfileView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
# request.user is guaranteed to be authenticated via Bearer token
return Response({'username': request.user.username, 'email': request.user.email})
2. Avoid exposing tokens in error messages and logs
Ensure DEBUG=False in production and sanitize any validation responses. Override exception handlers to remove sensitive details from tracebacks that might include Authorization headers.
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response is not None and 'detail' in response.data:
# Remove or generalize error details that might hint at token validity
response.data['detail'] = 'Authentication failed.'
return response
In settings, also disable request logging of Authorization headers:
import logging
logger = logging.getLogger('django.request')
class FilterAuthHeader(logging.Filter):
def filter(self, record):
if hasattr(record, 'request') and record.request:
# Remove Authorization header from logs
record.request.META.pop('HTTP_AUTHORIZATION', None)
return True
logger.addFilter(FilterAuthHeader())
3. Securely serve OpenAPI specs and remove hardcoded tokens
If using tools like drf-yasg or drf-spectacular, restrict schema access to authenticated staff only or serve it behind a firewall. Never include real Bearer tokens in examples.
# settings.py
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
# In your URL config
from django.urls import path
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView
urlpatterns = [
path('schema/', SpectacularAPIView.as_view(), name='schema'),
path('schema/redoc/', SpectacularRedocView.as_view(url_name='schema')),
]
Ensure that the schema view is not publicly exposed in production, or require a token to access /schema/ by wrapping it with a permission check.
4. Validate token scope and ownership
When returning user-specific data, always scope the query to the authenticated token’s user rather than trusting URL parameters.
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.contrib.auth.models import User
@api_view(['GET'])
def user_profile(request, username):
# Enforce that the requesting user can only view their own profile
if request.user.username != username:
return Response({'error': 'Access denied.'}, status=403)
user = User.objects.get(username=username)
return Response({'username': user.username, 'email': request.user.email})
5. Use HTTPS and short token lifetimes
Always serve Django behind HTTPS to prevent token interception. Prefer short-lived Bearer tokens and refresh token mechanisms to reduce the impact of any potential disclosure.
By combining strict permissions, careful error handling, and secure transport, Django APIs can safely use Bearer tokens without exposing sensitive information.