CVE-2026-3902 Overview
A header spoofing vulnerability has been discovered in Django's ASGIRequest class that allows remote attackers to exploit an ambiguous mapping between two header variants—those with hyphens and those with underscores—which are both normalized to a single version with underscores. This vulnerability affects Django versions 6.0 before 6.0.4, 5.2 before 5.2.13, and 4.2 before 4.2.30. Earlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected.
Critical Impact
Remote attackers can spoof HTTP headers in ASGI-based Django applications, potentially bypassing security controls that rely on header values for authentication, authorization, or request routing decisions.
Affected Products
- Django 6.0 before 6.0.4
- Django 5.2 before 5.2.13
- Django 4.2 before 4.2.30
Discovery Timeline
- April 7, 2026 - CVE-2026-3902 published to NVD
- April 8, 2026 - Last updated in NVD database
Technical Details for CVE-2026-3902
Vulnerability Analysis
This vulnerability (CWE-290: Authentication Bypass by Spoofing) exists in Django's ASGI request handling mechanism. The ASGIRequest class fails to properly disambiguate between HTTP headers that use hyphens (e.g., X-Forwarded-For) and those that use underscores (e.g., X_Forwarded_For). Both variants are normalized to a single underscore-based representation, creating an ambiguous mapping that attackers can exploit.
When an application relies on specific headers for security decisions—such as identifying client IP addresses, validating authentication tokens, or enforcing access controls—an attacker can craft malicious requests with duplicate header variants to inject spoofed values. This is particularly dangerous in applications deployed behind reverse proxies or load balancers that set trusted headers.
Root Cause
The root cause lies in the header normalization logic within the ASGIRequest class. HTTP headers with hyphens and underscores are treated as equivalent during the conversion process to Django's internal representation. This creates a race condition where an attacker-controlled header can take precedence over a legitimate header set by upstream infrastructure.
The ASGI specification permits headers to be passed through with minimal transformation, but Django's handling does not account for the security implications of this ambiguity. When both Content-Type and Content_Type are present in a request, the order of processing determines which value the application ultimately sees.
Attack Vector
The attack is network-based and requires no authentication or user interaction. An attacker sends HTTP requests to a vulnerable Django application with carefully crafted headers containing both hyphenated and underscore versions of security-sensitive headers.
For example, an attacker could send a request with both X-Forwarded-For: trusted-proxy-ip (set by the legitimate proxy) and X_Forwarded_For: attacker-controlled-ip in the same request. Depending on how Django processes these headers, the attacker's value may overwrite or take precedence over the trusted value.
The vulnerability is particularly severe in deployments where:
- Applications trust headers like X-Forwarded-For, X-Real-IP, or custom authentication headers
- ASGI servers are used (such as Daphne, Uvicorn, or Hypercorn)
- Security middleware or decorators make decisions based on header values
For detailed technical information on the exploitation mechanism, refer to the Django Security Release Notes.
Detection Methods for CVE-2026-3902
Indicators of Compromise
- Presence of duplicate headers in access logs with both hyphen and underscore variants (e.g., X-Forwarded-For and X_Forwarded_For)
- Unexpected IP addresses or values in headers that should be set by trusted infrastructure
- Authentication or authorization failures followed by successful access from the same source
- Anomalous request patterns containing malformed or duplicate HTTP headers
Detection Strategies
- Implement web application firewall (WAF) rules to detect and block requests containing both hyphen and underscore variants of the same header
- Deploy log analysis to identify requests with header naming collisions
- Use intrusion detection systems (IDS) with signatures for header spoofing attempts
- Monitor ASGI application logs for header normalization warnings or anomalies
Monitoring Recommendations
- Enable detailed header logging at the reverse proxy or load balancer level to capture all incoming headers before Django processing
- Set up alerts for requests containing underscore-based header names, which are non-standard in HTTP
- Implement application-level monitoring to track authentication decisions and correlate with header values
- Review access patterns for signs of IP spoofing or header manipulation attacks
How to Mitigate CVE-2026-3902
Immediate Actions Required
- Upgrade Django to patched versions: 6.0.4, 5.2.13, or 4.2.30 immediately
- Review application code for header-based security decisions that may be affected
- Configure reverse proxies to strip or reject requests with underscore-based header names
- Audit existing deployments for signs of exploitation
Patch Information
Django has released security patches addressing this vulnerability. The fixes are available in the following versions:
- Django 6.0.4 for the 6.0.x series
- Django 5.2.13 for the 5.2.x series
- Django 4.2.30 for the 4.2.x series (LTS)
Upgrade using pip: pip install --upgrade Django
For additional details, see the Django Weblog Security Releases and subscribe to the Django Announcements Group for future security notifications.
Workarounds
- Configure your reverse proxy (Nginx, Apache, HAProxy) to normalize or reject requests containing underscore-based header names before they reach Django
- Implement middleware to validate and sanitize incoming headers, rejecting requests with ambiguous header patterns
- If using ASGI, consider switching to WSGI temporarily if the application architecture permits, as WSGI may handle header normalization differently
- Restrict trusted header sources at the infrastructure level rather than relying solely on application-level header inspection
# Nginx configuration to reject underscore headers
# Add to server or location block
underscores_in_headers off;
# Apache configuration to reject requests with underscore headers
# Add to VirtualHost or .htaccess
RewriteEngine On
RewriteCond %{HTTP:X_Forwarded_For} .+
RewriteRule .* - [F,L]
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


