Low severityOSV Advisory· Published Feb 3, 2026· Updated Feb 3, 2026
Potential denial-of-service vulnerability via repeated headers when using ASGI
CVE-2025-14550
Description
An issue was discovered in 6.0 before 6.0.2, 5.2 before 5.2.11, and 4.2 before 4.2.28. ASGIRequest allows a remote attacker to cause a potential denial-of-service via a crafted request with multiple duplicate headers. Earlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected. Django would like to thank Jiyong Yang for reporting this issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
DjangoPyPI | >= 6.0a1, < 6.0.2 | 6.0.2 |
DjangoPyPI | >= 5.2a1, < 5.2.11 | 5.2.11 |
DjangoPyPI | >= 4.2a1, < 4.2.28 | 4.2.28 |
Affected products
1- Range: 4.2, 4.2.1, 4.2.10, …
Patches
1eb22e1d6d643Fixed CVE-2025-14550 -- Optimized repeated header parsing in ASGI requests.
5 files changed · +69 −6
django/core/handlers/asgi.py+6 −5 modified@@ -3,6 +3,7 @@ import sys import tempfile import traceback +from collections import defaultdict from contextlib import aclosing, closing from asgiref.sync import ThreadSensitiveContext, sync_to_async @@ -83,6 +84,7 @@ def __init__(self, scope, body_file): self.META["SERVER_NAME"] = "unknown" self.META["SERVER_PORT"] = "0" # Headers go into META. + _headers = defaultdict(list) for name, value in self.scope.get("headers", []): name = name.decode("latin1") if name == "content-length": @@ -96,11 +98,10 @@ def __init__(self, scope, body_file): value = value.decode("latin1") if corrected_name == "HTTP_COOKIE": value = value.rstrip("; ") - if "HTTP_COOKIE" in self.META: - value = self.META[corrected_name] + "; " + value - elif corrected_name in self.META: - value = self.META[corrected_name] + "," + value - self.META[corrected_name] = value + _headers[corrected_name].append(value) + if cookie_header := _headers.pop("HTTP_COOKIE", None): + self.META["HTTP_COOKIE"] = "; ".join(cookie_header) + self.META.update({name: ",".join(value) for name, value in _headers.items()}) # Pull out request encoding, if provided. self._set_content_type_params(self.META) # Directly assign the body file to be our stream.
docs/releases/4.2.28.txt+12 −0 modified@@ -17,3 +17,15 @@ allowed remote attackers to enumerate users via a timing attack. This issue has severity "low" according to the :ref:`Django security policy <security-disclosure>`. + +CVE-2025-14550: Potential denial-of-service vulnerability via repeated headers when using ASGI +============================================================================================== + +When receiving duplicates of a single header, ``ASGIRequest`` allowed a remote +attacker to cause a potential denial-of-service via a specifically created +request with multiple duplicate headers. The vulnerability resulted from +repeated string concatenation while combining repeated headers, which +produced super-linear computation resulting in service degradation or outage. + +This issue has severity "moderate" according to the :ref:`Django security +policy <security-disclosure>`.
docs/releases/5.2.11.txt+12 −0 modified@@ -17,3 +17,15 @@ allowed remote attackers to enumerate users via a timing attack. This issue has severity "low" according to the :ref:`Django security policy <security-disclosure>`. + +CVE-2025-14550: Potential denial-of-service vulnerability via repeated headers when using ASGI +============================================================================================== + +When receiving duplicates of a single header, ``ASGIRequest`` allowed a remote +attacker to cause a potential denial-of-service via a specifically created +request with multiple duplicate headers. The vulnerability resulted from +repeated string concatenation while combining repeated headers, which +produced super-linear computation resulting in service degradation or outage. + +This issue has severity "moderate" according to the :ref:`Django security +policy <security-disclosure>`.
docs/releases/6.0.2.txt+12 −0 modified@@ -18,6 +18,18 @@ allowed remote attackers to enumerate users via a timing attack. This issue has severity "low" according to the :ref:`Django security policy <security-disclosure>`. +CVE-2025-14550: Potential denial-of-service vulnerability via repeated headers when using ASGI +============================================================================================== + +When receiving duplicates of a single header, ``ASGIRequest`` allowed a remote +attacker to cause a potential denial-of-service via a specifically created +request with multiple duplicate headers. The vulnerability resulted from +repeated string concatenation while combining repeated headers, which +produced super-linear computation resulting in service degradation or outage. + +This issue has severity "moderate" according to the :ref:`Django security +policy <security-disclosure>`. + Bugfixes ========
tests/asgi/tests.py+27 −1 modified@@ -223,7 +223,7 @@ async def test_post_body(self): self.assertEqual(response_body["type"], "http.response.body") self.assertEqual(response_body["body"], b"Echo!") - async def test_create_request_error(self): + async def test_request_too_big_request_error(self): # Track request_finished signal. signal_handler = SignalHandler() request_finished.connect(signal_handler) @@ -254,6 +254,32 @@ class TestASGIHandler(ASGIHandler): signal_handler.calls[0]["thread"], threading.current_thread() ) + async def test_meta_not_modified_with_repeat_headers(self): + scope = self.async_request_factory._base_scope(path="/", http_version="2.0") + scope["headers"] = [(b"foo", b"bar")] * 200_000 + + setitem_count = 0 + + class InstrumentedDict(dict): + def __setitem__(self, *args, **kwargs): + nonlocal setitem_count + setitem_count += 1 + super().__setitem__(*args, **kwargs) + + class InstrumentedASGIRequest(ASGIRequest): + @property + def META(self): + return self._meta + + @META.setter + def META(self, value): + self._meta = InstrumentedDict(**value) + + request = InstrumentedASGIRequest(scope, None) + + self.assertEqual(len(request.headers["foo"].split(",")), 200_000) + self.assertLessEqual(setitem_count, 100) + async def test_cancel_post_request_with_sync_processing(self): """ The request.body object should be available and readable in view
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- docs.djangoproject.com/en/dev/releases/security/mitrevendor-advisory
- github.com/advisories/GHSA-33mw-q7rj-mjwjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-14550ghsaADVISORY
- www.djangoproject.com/weblog/2026/feb/03/security-releases/mitrevendor-advisory
- docs.djangoproject.com/en/dev/releases/securityghsaWEB
- github.com/django/django/commit/eb22e1d6d643360e952609ef562c139a100ea4ebghsaWEB
- groups.google.com/g/django-announceghsamailing-listWEB
- www.djangoproject.com/weblog/2026/feb/03/security-releasesghsaWEB
News mentions
1- How AI Assistants are Moving the Security GoalpostsKrebs on Security · Mar 8, 2026