CVE-2024-21520 Overview
CVE-2024-21520 is a Cross-Site Scripting (XSS) vulnerability [CWE-79] in the Django REST Framework (DRF) Python package. Versions of djangorestframework prior to 3.15.2 fail to sanitize user-controlled input in the break_long_headers template filter before splitting the value on commas and rejoining it with <br> tags. An attacker who can influence rendered header content may inject HTML or JavaScript that executes in the context of the browsable API.
The issue affects deployments that render the DRF browsable API and expose long, comma-separated header values back to users. Exploitation requires user interaction, and impact is limited to the browser session.
Critical Impact
Reflected script execution in the DRF browsable API can lead to session data theft, UI redressing, or targeted phishing against authenticated API consumers.
Affected Products
- djangorestframework versions prior to 3.15.2
- Django applications rendering the DRF browsable API with break_long_headers
- Downstream Python projects pinning vulnerable DRF releases
Discovery Timeline
- 2024-06-26 - CVE-2024-21520 published to NVD
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2024-21520
Vulnerability Analysis
The defect lives in rest_framework/templatetags/rest_framework.py inside the break_long_headers template filter. When a header string exceeds 160 characters and contains a comma, the filter splits the string on commas, rejoins it with <br> separators, and wraps the result with mark_safe(). Because mark_safe() tells Django's template engine to skip auto-escaping, any HTML or JavaScript already present in the header value is emitted verbatim into the rendered page.
The browsable API renders response headers through this filter, so header values reflected from a request or produced by upstream components become an injection sink. Users who load a crafted response through the browsable interface will execute the attacker-controlled markup in their browser session.
Root Cause
The root cause is missing output encoding before invoking mark_safe(). The pre-patch code trusted the header content and split it prior to escaping, so the raw substrings were concatenated into safe-marked HTML. This violates the standard XSS defense pattern of escaping untrusted data at the point of HTML construction.
Attack Vector
Exploitation is network-based and requires user interaction. An attacker crafts a request whose response headers, or a header echoed by the application, contains a comma-separated payload longer than 160 characters that includes HTML tags such as <script> or <img onerror=...>. A victim then visits the browsable API endpoint that renders the affected response, triggering script execution in the victim's origin context.
# Patch diff: rest_framework/templatetags/rest_framework.py
# Fix potential XSS vulnerability in break_long_headers template filter (#9435)
when possible (are comma separated)
"""
if len(header) > 160 and ',' in header:
- header = mark_safe('<br> ' + ', <br>'.join(header.split(',')))
+ header = mark_safe('<br> ' + ', <br>'.join(escape(header).split(',')))
return header
Source: GitHub Commit 3b41f01
Detection Methods for CVE-2024-21520
Indicators of Compromise
- Long, comma-separated response headers containing HTML tags such as <script>, <iframe>, or event handlers like onerror= and onload=.
- Browsable API responses reflecting request-controlled header values above 160 characters in length.
- Unusual outbound requests from browser sessions immediately after visiting DRF browsable API URLs.
Detection Strategies
- Inventory Python dependencies and flag any project pinning djangorestframework < 3.15.2 using tools such as pip-audit or Snyk.
- Enable Content Security Policy (CSP) reporting on Django applications to surface inline script execution attempts in the browsable API.
- Scan HTTP responses in a web proxy for header values containing HTML control characters and unusual length combined with commas.
Monitoring Recommendations
- Alert on web application firewall (WAF) events matching XSS signatures against DRF endpoints that serve the browsable API.
- Log and review requests whose headers contain script-like payloads or exceed expected header size limits.
- Track CSP violation reports scoped to Django administrative or API browsing paths to identify exploitation attempts.
How to Mitigate CVE-2024-21520
Immediate Actions Required
- Upgrade djangorestframework to version 3.15.2 or later across all environments.
- Audit templates that render user-controlled headers and confirm no custom filters replicate the unsafe mark_safe() pattern.
- Disable the DRF browsable API in production deployments where it is not required.
Patch Information
The fix landed in Django REST Framework 3.15.2 via Pull Request #9435 and commit 3b41f01. The patch wraps the header value with Django's escape() helper before splitting and joining, ensuring HTML metacharacters are neutralized prior to mark_safe(). See the 3.15.1 to 3.15.2 diff and the Snyk advisory SNYK-PYTHON-DJANGORESTFRAMEWORK-7252137 for additional context.
Workarounds
- Restrict access to the browsable API using authentication or IP allow-lists until the upgrade is deployed.
- Set DEFAULT_RENDERER_CLASSES to exclude BrowsableAPIRenderer in production settings.
- Deploy a strict Content Security Policy that disallows inline script execution on browsable API paths.
# Pin the patched version in requirements.txt
echo "djangorestframework>=3.15.2" >> requirements.txt
pip install --upgrade "djangorestframework>=3.15.2"
# Optional: disable BrowsableAPIRenderer in Django settings.py
# REST_FRAMEWORK = {
# 'DEFAULT_RENDERER_CLASSES': (
# 'rest_framework.renderers.JSONRenderer',
# ),
# }
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

