Sep 1, 2026·6 min read·23 visits
Django REST Framework bypassed Django's native DATA_UPLOAD_MAX_MEMORY_SIZE configuration, letting unauthenticated attackers exhaust system memory and trigger Out-Of-Memory (OOM) crashes by sending massive JSON or URL-encoded payloads.
A vulnerability in Django REST Framework (DRF) before version 3.17.2 allows remote attackers to bypass the native Django DATA_UPLOAD_MAX_MEMORY_SIZE limits. When parsing JSON or URL-encoded request bodies, DRF's JSONParser and FormParser read directly from the low-level HTTP network stream, bypassing Django's high-level request size checks and causing Denial of Service (DoS) via resource exhaustion.
Django REST Framework (DRF) before version 3.17.2 is vulnerable to uncontrolled resource consumption because it fails to enforce native request size constraints during the parsing process. Under normal execution, Django mitigates denial-of-service attempts by setting a global size limit on raw payloads using the DATA_UPLOAD_MAX_MEMORY_SIZE setting. Any access to high-level properties like request.body evaluates this threshold and terminates oversized requests with a RequestDataTooBig exception. This safeguard ensures that standard Django views are protected from being flooded with large payloads that could crash the application server.
However, the Django REST Framework architecture introduces a technical gap. Inside rest_framework/request.py, DRF intercepts incoming requests and invokes specialized parsers like JSONParser and FormParser to handle incoming JSON or form-encoded payloads. Because these parsers read directly from the raw, low-level streaming interface of Django's request, they bypass Django's validation checks. This behavior exposes a significant attack surface on any endpoint configured to receive client data.
This architectural gap allows remote, unauthenticated attackers to submit exceptionally large HTTP requests to any endpoint processing JSON or form data. The application allocates system memory dynamically to consume this input stream, resulting in memory depletion and CPU exhaustion. The resulting resource depletion frequently leads to process termination by the operating system, creating an application-layer denial of service.
To analyze the technical root cause, we must examine the difference between high-level request properties and low-level streams in Django. When a request reaches Django, the raw HTTP socket is presented as an input stream. Standard Django views consume this stream when the developer references request.body or request.POST. The loading code explicitly checks the size of the incoming stream, raising a RequestDataTooBig exception if the size exceeds DATA_UPLOAD_MAX_MEMORY_SIZE.
In contrast, DRF delegates payload reading to parsing classes like JSONParser or FormParser. To parse efficiently, DRF hands the raw stream directly to these parsers. The parser reads from the socket and decodes the stream iteratively. Because this bypasses request.body or request.POST accesses, Django's native checks are never triggered, allowing an attacker to transmit large quantities of data directly to the parser.
Once the parser begins reading the payload, it allocates heap memory to hold the raw stream bytes. The Python JSON parser then deserializes these bytes, creating complex data structures such as deeply nested dictionaries and arrays. The memory required to store these parsed objects is often multiple times larger than the raw string size, causing memory usage to escalate. If several such requests are processed concurrently, the host operating system or container run-time runs out of memory and terminates the application worker process.
The following diagram illustrates the vulnerable execution path versus the patched validation flow:
The vulnerability was fixed in Django REST Framework 3.17.2 by forcing Django to evaluate the request size before the parser begins reading the input stream. This fix was introduced in the rest_framework/request.py file within the Request._parse() method. The modification intercepts the parsing pipeline when a standard JSON or form-encoded parser is selected.
The patched implementation implements dynamic imports to prevent circular dependencies in DRF initialization, followed by an explicit type check:
# Patched implementation in rest_framework/request.py
def _parse(self):
# ... configuration and parser selection ...
if not parser:
raise exceptions.UnsupportedMediaType(media_type)
# Dynamic imports prevent circular dependencies in DRF initialization
from rest_framework.parsers import FormParser, JSONParser
# Check if the chosen parser is an instance of JSONParser or FormParser
if isinstance(parser, (JSONParser, FormParser)):
# Accessing self.body forces Django's native limits validation
stream = io.BytesIO(self.body)
try:
parsed = parser.parse(stream, media_type, self.parser_context)
except Exception:
# ... exception handling ...By accessing self.body, DRF triggers Django's high-level request size evaluation. If the payload is too large, Django raises RequestDataTooBig and aborts execution before the parsing logic can run. If the size is valid, Django caches the payload and returns the raw bytes. The patch wraps these validated bytes in an io.BytesIO stream, providing a safe, bounded source for the parser to consume.
A critical review of this patch reveals a potential limitation. The code relies on an explicit type check using isinstance(parser, (JSONParser, FormParser)). Any custom or third-party parser that does not inherit directly from these classes will bypass this check and continue reading from the raw, unchecked stream. Security researchers and developers must evaluate custom parser classes to ensure they do not expose the application to similar resource depletion attacks.
Exploiting this vulnerability does not require authenticated sessions or sophisticated technical knowledge. An attacker must simply locate an API endpoint that processes JSON or URL-encoded form data. Because many public-facing APIs (such as registration and login screens) accept these media types without requiring authentication, the attack surface is substantial.
The attacker constructs a large JSON payload consisting of a single key with a long string value or deeply nested dictionaries. Sending a 100 megabyte payload over a slow connection allows the attacker to hold the connection open, consuming resources incrementally. When the application worker tries to parse the 100 megabyte payload, memory allocations can balloon to 400 or 500 megabytes because of Python object overhead.
If the attacker coordinates multiple concurrent requests, they can consume all available RAM on the application server. The kernel's Out-Of-Memory (OOM) killer will intervene, killing the WSGI or ASGI process and causing a denial of service. The service remains unavailable until the process manager (such as Gunicorn or uWSGI) spawns new worker instances.
The primary and recommended solution is to upgrade Django REST Framework to version 3.17.2 or higher. This upgrade updates the _parse method to validate incoming stream sizes automatically. Developers should execute pip install --upgrade djangorestframework>=3.17.2 to apply this change immediately.
If upgrading the library is not immediately possible, several secondary defenses can be deployed. A web application firewall (WAF) or reverse proxy can enforce strict payload size limits at the network edge, preventing large requests from reaching the application server. For example, adding client_max_body_size 5M; to the NGINX configuration block restricts request payloads before they are passed to the WSGI socket.
Alternatively, custom middleware can be added to the Django application pipeline to force validation of all incoming JSON and form-encoded requests. This middleware intercepts requests and accesses request.body before DRF routes the request to a view. If the request exceeds the allowed limit, Django's native handler blocks the request and returns a clean HTTP 400 response, neutralizing the attack path.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
django-rest-framework encode | < 3.17.2 | 3.17.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 / CWE-770 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.3 (Medium) |
| Exploit Maturity | PoC / Functional |
| CISA KEV | Not Listed |
| Affected Component | rest_framework/request.py (Request._parse) |
The software does not properly control the allocation and maintenance of a limited resource, enabling an actor to cause resource depletion.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.
An elevation of privilege vulnerability exists in ASP.NET Core and Microsoft Visual Studio due to improper synchronization during concurrent thread execution. Authenticated remote attackers with low privileges can exploit a timing window to manipulate shared resources and assume higher-level execution contexts.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.