Xml External Entities in Django with Bearer Tokens
Xml External Entities in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability
An XML External Entity (XXE) vulnerability in Django can intersect with Bearer Token authentication in ways that amplify impact. When an API endpoint accepts XML payloads and processes them with Python XML parsers that resolve external entities, an attacker can leverage the trust boundary introduced by Bearer Tokens to escalate the attack surface.
Consider an endpoint that expects a Bearer Token in the Authorization header and also accepts XML in the request body. If the server-side XML parser is configured to resolve external entities (e.g., using defusedxml is not applied), an attacker can embed malicious entity definitions that reference local files, remote URLs, or internal services. Because the request includes a valid Bearer Token, the request may be authenticated and authorized, causing the server to inadvertently process the malicious XML in the context of the permissions granted by that token.
For example, an authenticated request with a Bearer Token might look like this:
POST /api/import HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c Content-Type: application/xml ]>&xxe;
If the server parses this XML without disabling external entity resolution, the file:///etc/passwd reference can be read and returned in any error messages or logs. In some configurations, attackers can also force the server to make outbound HTTP requests to exfiltrate data to a remote attacker-controlled endpoint, especially if the Django app acts as an HTTP client. The presence of a Bearer Token does not cause the XXE, but it can ensure the malicious XML reaches a code path that would otherwise be restricted, increasing the risk of sensitive data exposure or SSRF.
Django does not include built-in XML parsing in its core; developers typically add libraries such as lxml or xml.etree. If these libraries are used without secure defaults (e.g., disabling external entities), the application becomes vulnerable. Because middleBrick tests the unauthenticated attack surface but also supports authenticated scans where credentials are provided, it can detect whether XXE-prone parsing is present in endpoints that require Bearer Tokens, helping teams correlate authentication context with XML handling risks.
Bearer Tokens-Specific Remediation in Django — concrete code fixes
Remediation focuses on two areas: ensuring XML parsing does not resolve external entities, and securely handling Bearer Tokens to avoid unintended authorization bypass or data exposure. Below are concrete, safe patterns for Django projects.
1. Secure XML parsing (disable external entities)
Use defusedxml for all XML processing. If you parse XML manually, configure parsers to reject external entities and external DTDs.
import defusedxml.ElementTree as ET
def parse_safe_xml(xml_data: bytes):
# Disables external entities and DTDs by default in defusedxml
root = ET.fromstring(xml_data)
return root
If you use lxml, disable external entities explicitly:
from lxml import etree
def parse_lxml_safe(xml_data: bytes):
parser = etree.XMLParser(resolve_entities=False, no_network=True, load_dtd=False)
root = etree.fromstring(xml_data, parser=parser)
return root
2. Bearer Token handling and validation
Always validate and scope Bearer Tokens. Use Django REST Framework’s permission classes and avoid processing requests with malformed or missing tokens.
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.response import Response
class SecureImportView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
# request.auth is set only if token is valid and not expired
# Ensure the token has appropriate scopes for this operation
if not request.auth or not request.auth.has_scope('import:data'):
return Response({'detail': 'Insufficient scope.'}, status=403)
# Safe XML parsing as defined above
xml_data = request.body
try:
root = parse_safe_xml(xml_data)
except Exception as e:
return Response({'detail': 'Invalid XML'}, status=400)
# Process data with the permissions of the authenticated token
return Response({'status': 'ok'})
For token validation, prefer well-audited libraries such as djangorestframework-simplejwt and explicitly check token expiration and scopes. Never trust the presence of a Bearer Token alone to determine what an XML payload is allowed to do.
3. Middleware and request validation
Add validation early in the request lifecycle to reject XML when JSON is expected, or enforce strict content-type checks to reduce the attack surface.
from django.utils.deprecation import MiddlewareMixin
class RestrictXmlMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.method == 'POST' and 'application/xml' in request.content_type:
# Only allow XML on specific endpoints; otherwise reject
if not request.path.startswith('/api/import'):
return HttpResponseForbidden('XML not allowed on this endpoint')
These measures ensure that even if a request carries a valid Bearer Token, the server will not inadvertently process malicious external entities, and token permissions remain tightly coupled with safe data handling.