Django REST framework: JSONParser memory exhaustion via charset parameter
Django REST framework (DRF) JSONParser fails to validate charset codecs, allowing attackers to bypass DATA_UPLOAD_MAX_MEMORY_SIZE limits through malicious compression, leading to significant memory amplification.
Triage facts
Revision 1- Applicability
- Django REST framework (>= 3.6.4)
- Evidence
- Unknown
- Severity
- High
- Action
- Elevated
- Sources
- 1 public source
- Freshness
- Revision 1Oct 29, 22:22 UTC
- Source quality
- A1Likely
Django REST framework (DRF) versions 3.6.4 and later contain a vulnerability in JSONParser where the Content-Type charset parameter is used to apply arbitrary codecs to the request stream. Because DRF does not verify if the requested charset is a valid text encoding, an attacker can specify byte-transform codecs like bz2_codec or zlib_codec. This results in the request body being decompressed into memory before the DATA_UPLOAD_MAX_MEMORY_SIZE check is performed, allowing for massive memory expansion.
Attack Chain
- Attacker crafts a highly compressed malicious JSON payload (e.g., 108 bytes).
- Attacker initiates a POST request to a DRF endpoint accepting JSON.
- Attacker sets the
Content-Typeheader toapplication/json; charset=bz2_codec. - Django receives the request and initializes
JSONParser. JSONParsercallscodecs.getreader()with the attacker-providedbz2_codec.- The request stream is decompressed into memory by the codec reader.
- The expanded data is passed to
json.load()while the originalDATA_UPLOAD_MAX_MEMORY_SIZEcheck remains satisfied by the small wire-size of the payload. - The worker process consumes significant memory, potentially causing a Denial of Service (DoS).
Impact
The vulnerability allows an amplification factor of over 400,000x, where a 108-byte request can force the allocation of ~50 MiB of memory, significantly increasing process peak RSS and facilitating memory-based DoS.
Recommendation
Patch the JSONParser to validate that the provided encoding is a supported text-based encoding. Implement the following check within rest_framework/parsers.py before invoking the codec:
import codecs
from rest_framework.exceptions import ParseError
if not codecs.lookup(encoding)._is_text_encoding:
raise ParseError('Unsupported charset in Content-Type')
Until patches are applied, monitor for unusual Content-Type headers containing non-standard charset parameters in application access logs.
Immediate actions
Identify all services using Django REST framework and verify version
Threat Hunt
Identify HTTP POST requests with Content-Type charset parameters indicative of compression codecs
Data: Web server access logs, Application request headers
Mitigations
Apply the suggested codec lookup validation check in rest_framework/parsers.py
JSONParser charset codec amplification