Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-15337

CVE-2026-15337: Django Translation DoS Vulnerability

CVE-2026-15337 is a denial-of-service vulnerability in Django's translation module that allows attackers to exhaust memory via long language codes. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-15337 Overview

CVE-2026-15337 is a denial-of-service vulnerability in the Django web framework. The issue affects django.utils.translation.check_for_language(), which retains distinct language codes as keys in an in-memory cache. An attacker can supply many long, unique language codes through the django.views.i18n.set_language() view, consuming process memory. The affected versions are Django 5.2 before 5.2.17 and Django 6.0 before 6.0.8. Earlier unsupported series (5.1.x, 5.0.x, 4.2.x) were not evaluated and may also be affected. The set_language() view is not routed by default, which limits real-world exposure. Memory consumption is bounded by the DATA_UPLOAD_MAX_MEMORY_SIZE setting (default 2.5 MB) and the cache's fixed maximum entry count.

Critical Impact

Remote unauthenticated attackers can trigger memory exhaustion in Django applications that expose the set_language() view, degrading service availability. [CWE-789]

Affected Products

  • Django 5.2 (before 5.2.17)
  • Django 6.0 (before 6.0.8)
  • Earlier unsupported series (5.1.x, 5.0.x, 4.2.x) may also be affected but were not evaluated

Discovery Timeline

  • Vulnerability reported by Jaeyoung Jang to the Django security team
  • 2026-08-04 - Django releases security patches (5.2.17 and 6.0.8) via the Django Weblog Security Releases
  • 2026-08-04 - CVE-2026-15337 published to NVD
  • 2026-08-04 - Last updated in NVD database

Technical Details for CVE-2026-15337

Vulnerability Analysis

The vulnerability is a memory-exhaustion denial-of-service issue classified under [CWE-789] (Memory Allocation with Excessive Size Value). Django's translation subsystem caches validation results for language codes to avoid repeated file system lookups. Each new language code becomes a distinct cache key. When an attacker submits many long, unique language codes, the cache grows and consumes process memory. The vulnerable path is reachable only through django.views.i18n.set_language(), which applications must explicitly route.

Root Cause

The root cause is unbounded input length in check_for_language(). Before the patch, the function accepted language codes of arbitrary length and inserted them into an in-memory cache. Attacker-controlled strings passed through the set_language() view flowed directly into cache keys. Django did not enforce a maximum length on individual lang_code values before performing the language-file lookup and cache insertion.

Attack Vector

An unauthenticated remote attacker sends repeated POST requests to the set_language() endpoint, each containing a long, unique language value. Each request consumes cache space and memory. The DATA_UPLOAD_MAX_MEMORY_SIZE setting (default 2.5 MB) limits per-request payload size, and the language cache has a fixed maximum entry count, so total memory consumption is bounded but still degrades performance.

python
# Django patch: django/utils/translation/trans_real.py
# Source: https://github.com/django/django/commit/27137e655e442e81095f1f8f77ff3870d9fdf169

# magic gettext number to separate context from message
CONTEXT_SEPARATOR = "\\x04"

# Maximum length of a language code that will be processed, to prevent possible
# denial of service or memory exhaustion attacks. Language codes are taken from
# the Accept-Language header, the language cookie, the URL path prefix, or the
# set_language() view. 500 is about 10x the longest value shown on MDN's
# Accept-Language page.
LANGUAGE_CODE_MAX_LENGTH = 500

The patch enforces a 500-character maximum on lang_code. Values exceeding this limit return False immediately, before any language-file lookup or cache insertion. See the Django commit for 6.0.x.

Detection Methods for CVE-2026-15337

Indicators of Compromise

  • High volume of POST requests to the set_language() view, typically routed at /i18n/setlang/ or similar paths
  • Request bodies containing unusually long language parameter values approaching the DATA_UPLOAD_MAX_MEMORY_SIZE limit
  • Sustained growth of Django worker process memory correlated with i18n endpoint traffic
  • Repeated requests from the same source with distinct, high-entropy language values

Detection Strategies

  • Inspect web server access logs for POST requests to i18n endpoints and alert on request rate anomalies
  • Add application-level logging around set_language() invocations, recording language parameter length
  • Compare deployed Django version against 5.2.17 and 6.0.8 using dependency scanning tools
  • Monitor Python process resident set size (RSS) for gradual increases without corresponding legitimate traffic

Monitoring Recommendations

  • Track memory utilization of WSGI or ASGI worker processes and alert on sustained upward trends
  • Instrument the django.views.i18n.set_language view with request rate and payload-size metrics
  • Correlate i18n endpoint traffic against baseline usage patterns using a centralized log platform
  • Review whether set_language() is routed in urls.py and whether it is exposed to unauthenticated users

How to Mitigate CVE-2026-15337

Immediate Actions Required

  • Upgrade Django to 5.2.17 or 6.0.8 using the official releases described in the Django Security Release Notes
  • Audit urls.py for inclusion of django.views.i18n routes and remove them if internationalization switching is not required
  • Apply rate limiting at the reverse proxy or WAF layer to POST requests targeting set_language()
  • Review whether unsupported Django series (5.1.x, 5.0.x, 4.2.x) are in use and plan migration to a supported release

Patch Information

Django released fixed versions 5.2.17 and 6.0.8 on 2026-08-04. The fix introduces a LANGUAGE_CODE_MAX_LENGTH = 500 constant in django/utils/translation/trans_real.py. Values longer than 500 characters cause check_for_language() to return False immediately, preventing cache pollution. Relevant commits: 27137e6, 224dbc8, and 5b3523d.

Workarounds

  • Remove or comment out path('i18n/', include('django.views.i18n')) from urls.py if language switching via HTTP is not required
  • Enforce request rate limits and payload size restrictions on the set_language() endpoint at the reverse proxy
  • Lower the DATA_UPLOAD_MAX_MEMORY_SIZE setting to further constrain accepted request body size
  • Place the i18n endpoints behind authentication middleware to prevent unauthenticated access
bash
# Upgrade Django to a patched release
pip install --upgrade 'Django>=5.2.17,<5.3'
# or
pip install --upgrade 'Django>=6.0.8,<6.1'

# Verify installed version
python -c "import django; print(django.get_version())"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.