summaryrefslogtreecommitdiff
path: root/django/http/multipartparser.py
diff options
context:
space:
mode:
authorNatalia <124304+nessita@users.noreply.github.com>2026-03-05 14:41:44 -0300
committerJacob Walls <jacobtylerwalls@gmail.com>2026-04-07 07:42:38 -0400
commitf13c20f81b56108ac477213fa5ada2524b5e5c98 (patch)
tree5e985054f208191268031a562e57d7533922f890 /django/http/multipartparser.py
parentabfe1a1c57a57cfaf6dd4a0571c029401a0fe743 (diff)
[4.2.x] Fixed CVE-2026-33033 -- Mitigated potential DoS in MultiPartParser.
When a multipart file part used `Content-Transfer-Encoding: base64` and the non-whitespace base64 bytes did not align to a multiple of 4 within a chunk, the parser entered a loop calling `field_stream.read(1-3)` once per whitespace byte. Each such call fetched the entire internal buffer, sliced off 1-3 bytes, and pushed the remainder back via unget(), doing an O(n) memory copy per call. A 2.5 MB payload of mostly whitespace produced CPU amplification relative to a normal upload of the same size. The alignment loop now reads `self._chunk_size` bytes at a time, and accumulates stripped parts in a list joined once at the end. Thanks to Seokchan Yoon for the report and the fixing patch. Backport of 7e9885f99cee771b51692fadc5592bdbf19641aa from main.
Diffstat (limited to 'django/http/multipartparser.py')
-rw-r--r--django/http/multipartparser.py15
1 files changed, 9 insertions, 6 deletions
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index 5ab63455ef..856ab68059 100644
--- a/django/http/multipartparser.py
+++ b/django/http/multipartparser.py
@@ -302,15 +302,18 @@ class MultiPartParser:
# We should always decode base64 chunks by
# multiple of 4, ignoring whitespace.
- stripped_chunk = b"".join(chunk.split())
+ stripped_parts = [b"".join(chunk.split())]
+ stripped_length = len(stripped_parts[0])
- remaining = len(stripped_chunk) % 4
- while remaining != 0:
- over_chunk = field_stream.read(4 - remaining)
+ while stripped_length % 4 != 0:
+ over_chunk = field_stream.read(self._chunk_size)
if not over_chunk:
break
- stripped_chunk += b"".join(over_chunk.split())
- remaining = len(stripped_chunk) % 4
+ over_stripped = b"".join(over_chunk.split())
+ stripped_parts.append(over_stripped)
+ stripped_length += len(over_stripped)
+
+ stripped_chunk = b"".join(stripped_parts)
try:
chunk = base64.b64decode(stripped_chunk)