CVE-2026-77050 Overview
CVE-2026-77050 is a denial-of-service vulnerability in Django's internationalization framework. The flaw resides in django.utils.translation.get_supported_language_variant(), which caches language codes as keys in an in-memory dictionary without enforcing length limits. Attackers can submit many distinct, very long language codes to exhaust process memory on the targeted application server. The issue affects Django 6.1 before 6.1.2, Django 6.0 before 6.0.9, and Django 5.2 before 5.2.18. Earlier unsupported series such as 5.1.x, 5.0.x, and 4.2.x may also be affected but were not evaluated. The vulnerability is classified under [CWE-789: Memory Allocation with Excessive Size Value]. Django credits Gleb Lizunov for reporting the issue.
Critical Impact
Unauthenticated remote attackers can trigger memory exhaustion in Django worker processes, degrading availability of web applications that process Accept-Language or similar user-controlled language inputs.
Affected Products
- Django 6.1 before 6.1.2
- Django 6.0 before 6.0.9
- Django 5.2 before 5.2.18
Discovery Timeline
- Vulnerability reported to Django by Gleb Lizunov
- 2026-10-06 - Django releases security advisory and patched versions 6.1.2, 6.0.9, and 5.2.18
- 2026-10-06 - CVE-2026-77050 published to NVD
- 2026-10-06 - Last updated in NVD database
Technical Details for CVE-2026-77050
Vulnerability Analysis
The vulnerability exists in django.utils.translation.trans_real.get_supported_language_variant(). Django resolves language codes supplied through HTTP headers (notably Accept-Language), URL prefixes, cookies, or session data to a supported language variant. To avoid repeated resolution work, the function uses an unbounded in-process cache keyed by the raw language code string.
Because input validation did not restrict the length of these keys, an attacker could issue requests containing arbitrarily long language codes. Each unique string became a persistent cache entry, growing the resident memory of the worker process until it was killed or the host ran out of memory. Affected applications experience service degradation, worker restarts, or outright denial of service.
Root Cause
The root cause is missing input bounds enforcement before caching. The function get_supported_language_variant() was decorated with a memoization cache that accepted language codes of any length. The patch extracts the cached lookup into an inner function _get_supported_language_variant() and places length validation in front of the cache boundary, so oversized values never populate the cache.
Attack Vector
The attack vector is network-based and requires no authentication or user interaction. An attacker sends repeated HTTP requests to any endpoint that reaches the Django language resolution path. Each request supplies a distinct, very long value in a header or parameter that Django parses as a language code. Over many requests the per-process cache grows until memory is exhausted.
# Patch excerpt - django/utils/translation/trans_real.py
if setting in ("LANGUAGES", "LANGUAGE_CODE"):
translation_catalog_exists.cache_clear()
get_languages.cache_clear()
- get_supported_language_variant.cache_clear()
+ _get_supported_language_variant.cache_clear()
class TranslationCatalog:
Source: GitHub Commit #02a69e3
The fix refactors the cached implementation into _get_supported_language_variant() and, per the release notes, rejects or truncates language codes longer than 500 characters before the cached lookup occurs.
Detection Methods for CVE-2026-77050
Indicators of Compromise
- Sustained growth in Django worker process resident memory not correlated with legitimate traffic volume
- Repeated HTTP requests containing unusually long Accept-Language header values or URL language prefixes
- WSGI or ASGI worker restarts triggered by out-of-memory conditions on application servers
- Elevated 5xx error rates coinciding with memory pressure on Django hosts
Detection Strategies
- Inspect reverse proxy and web server logs for Accept-Language header values exceeding typical BCP 47 length (usually under 35 characters)
- Correlate per-process memory metrics with request rates to identify slow-growth exhaustion patterns distinct from traffic spikes
- Alert on repeated unique language code values originating from the same source IP or user agent within short time windows
Monitoring Recommendations
- Instrument Django worker memory with Prometheus or equivalent and alert on monotonically increasing RSS across request cycles
- Enable web application firewall rules to log and rate-limit requests with oversized header fields
- Track LocaleMiddleware and translation subsystem call volumes to establish a baseline for anomaly detection
How to Mitigate CVE-2026-77050
Immediate Actions Required
- Upgrade Django to version 6.1.2, 6.0.9, or 5.2.18 depending on your supported release series
- Audit middleware chains for use of LocaleMiddleware and any custom code calling get_supported_language_variant()
- Deploy perimeter controls to reject HTTP requests with Accept-Language headers above a sensible length (for example 500 bytes)
- Restart Django worker processes after patching to clear any previously accumulated cache entries
Patch Information
The Django project released patched versions on 2026-10-06. The relevant commits are GitHub Commit #02a69e3 for the 5.2.x branch, GitHub Commit #3d32ee8 for the 6.0.x branch, GitHub Commit #7e878b0 for the 6.1.x branch, and GitHub Commit #c88b304. Full details are available in the Django Weblog Security Releases and Django Security Releases Documentation.
Workarounds
- Enforce a maximum length on the Accept-Language header at an upstream proxy such as Nginx, HAProxy, or a web application firewall
- Add a custom middleware ahead of LocaleMiddleware that truncates or rejects oversized language code values before Django processes them
- Set memory limits and automatic worker recycling (for example --max-requests in Gunicorn) to contain the blast radius until patches are applied
# Nginx example: cap Accept-Language header length and overall header size
http {
large_client_header_buffers 4 2k;
map $http_accept_language $al_too_long {
default 0;
"~^.{500,}$" 1;
}
server {
if ($al_too_long) {
return 400;
}
# proxy_pass to Django upstream
}
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.