HIGH xml external entitiesdjango

Xml External Entities in Django

How Xml External Entities Manifests in Django

Xml External Entities (XXE) vulnerabilities in Django applications typically arise when developers use XML parsing libraries without proper configuration, allowing attackers to read files, access internal services, or perform server-side request forgery through crafted XML payloads.

Django itself doesn't directly parse XML in its core request handling, but XXE vulnerabilities commonly appear in these Django-specific contexts:

  • REST Framework XML Parsers - When using rest_framework_xml or similar packages that enable XML content negotiation
  • Configuration Files - Settings files that accept XML input for feature flags or dynamic configuration
  • Third-party Integrations - Payment gateways, document processing services, or external APIs that exchange XML data
  • Custom Admin Interfaces - Admin views that allow XML file uploads or processing
  • Middleware Processing - Custom middleware that parses XML from request bodies or headers

The most dangerous Django-specific attack pattern involves uploading XML files through admin interfaces. Consider this vulnerable admin configuration:

from django.contrib import admin
from .models import Document

@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
    list_display = ['name', 'uploaded_at']
    # Vulnerable: allows XML file uploads without validation

An attacker could upload a malicious XML file containing:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<foo>&xxe;</foo>

When this XML is parsed by a vulnerable library, it could expose sensitive system files, internal network services, or even trigger SSRF attacks against internal Django services.

Django-Specific Detection

Detecting XXE vulnerabilities in Django applications requires examining both code patterns and runtime behavior. Here's how to identify potential XXE issues in your Django codebase:

Code Analysis Patterns

Search your Django project for these vulnerable patterns:

# Vulnerable: Using xml.etree.ElementTree without disabling entities
import xml.etree.ElementTree as ET

# Vulnerable: Using lxml without entity resolution disabled
from lxml import etree

# Vulnerable: Using xml.dom.minidom without proper configuration
import xml.dom.minidom as minidom

Look for these specific function calls in your views, serializers, or utilities:

ET.parse(file)  # Vulnerable if file is user-controlled
ET.fromstring(xml_data)  # Vulnerable if xml_data is untrusted
etree.parse(file)  # Vulnerable without parser options
etree.fromstring(xml_data)  # Same vulnerability

Content-Type Header Analysis

Check your Django REST Framework settings for XML parsers:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_xml.parsers.XMLParser',  # Potential XXE vector
        'rest_framework.parsers.JSONParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_xml.renderers.XMLRenderer',
        'rest_framework.renderers.JSONRenderer',
    ]
}

Automated Scanning with middleBrick

middleBrick's black-box scanning approach is particularly effective for detecting XXE vulnerabilities in Django applications. The scanner tests for XXE by:

  • Sending crafted XML payloads to endpoints that accept XML content types
  • Checking for XML parsing errors that might indicate vulnerable configurations
  • Testing for entity expansion and external entity resolution
  • Scanning OpenAPI specs for XML endpoints that might be vulnerable

Run middleBrick from your terminal:

middlebrick scan https://your-django-app.com/api/

The scanner will automatically detect XML endpoints and test them for XXE vulnerabilities, providing specific findings with severity levels and remediation guidance.

Django-Specific Remediation

Securing Django applications against XXE requires both secure coding practices and proper library configuration. Here are Django-specific remediation strategies:

Secure XML Parsing Configuration

For Python's standard library xml.etree.ElementTree:

import xml.etree.ElementTree as ET
from xml.parsers.expat import ParserCreate

# Secure parsing - disable entity resolution
def parse_xml_secure(xml_data):
    parser = ET.XMLParser(resolve_entities=False)
    return ET.fromstring(xml_data, parser=parser)

# Alternative using expat parser
def parse_xml_expat(xml_data):
    parser = ParserCreate()
    parser.StartNamespaceDeclHandler = None
    parser.EndNamespaceDeclHandler = None
    parser.DefaultHandlerExpand = None
    return ET.fromstring(xml_data, parser=parser)

For lxml library (recommended for Django applications):

from lxml import etree

def parse_xml_lxml_secure(xml_data):
    parser = etree.XMLParser(resolve_entities=False, load_dtd=False)
    return etree.fromstring(xml_data, parser=parser)

# For parsing files
def parse_file_lxml_secure(file_path):
    parser = etree.XMLParser(resolve_entities=False, load_dtd=False)
    with open(file_path, 'rb') as f:
        return etree.parse(f, parser=parser)

Django REST Framework Security

Configure your DRF settings to use secure parsers:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',  # Prefer JSON over XML
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
        # Remove XMLParser or use custom secure implementation
    ],
}

Admin Interface Protection

Secure your Django admin file uploads:

from django.contrib import admin
from .models import Document
from django import forms

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = '__all__'
    
    def clean_file(self):
        file = self.cleaned_data.get('file')
        if file and file.name.endswith(('.xml', '.xsd', '.xsl')):
            # Reject XML files or scan them
            raise forms.ValidationError('XML file uploads are not permitted')
        return file

@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
    form = DocumentForm
    list_display = ['name', 'uploaded_at']

Middleware Security

Add XXE protection at the middleware level:

class XXESecurityMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # Block XML content types for sensitive endpoints
        if 'CONTENT_TYPE' in request.META:
            content_type = request.META['CONTENT_TYPE']
            if 'xml' in content_type.lower():
                # Log and reject XML content for sensitive views
                if request.path.startswith('/admin/'):
                    return HttpResponseForbidden('XML content not allowed')
        
        return self.get_response(request)

Frequently Asked Questions

How can I test if my Django application is vulnerable to XXE?
Use middleBrick's automated scanning by running middlebrick scan https://your-django-app.com. The scanner tests for XXE by sending crafted XML payloads to endpoints that accept XML content types. Additionally, manually check your code for XML parsing without entity resolution disabled, and review your DRF settings for XML parsers.
Does Django's built-in request parsing protect against XXE?
Django's core request parsing (for form data, JSON, etc.) doesn't parse XML by default, so it's not vulnerable to XXE. However, when you add XML support through third-party packages or custom code, you need to explicitly configure secure XML parsing. Django itself doesn't provide XML parsing utilities, so the security depends on the libraries you choose to use.