VAITP Dataset

← Back to the dataset

CVE-2026-40347

Python-Multipart DoS via large preamble/epilogue in multipart requests.

  • CVSS 5.3
  • CWE-400
  • Resource Management
  • Remote

Python-Multipart is a streaming multipart parser for Python. Versions prior to 0.0.26 have a denial of service vulnerability when parsing crafted `multipart/form-data` requests with large preamble or epilogue sections. Upgrade to version 0.0.26 or later, which skips ahead to the next boundary candidate when processing leading CR/LF data and immediately discards epilogue data after the closing boundary.

CVSS base score
5.3
Published
2026-04-18
OWASP
A04 Insecure Design
Orthogonal defect classification
Algorithm
Code defect classification
Incorrect Algorithm
Category
Resource Management
Subcategory
Resource Exhaustion
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
Python-Multi
Fixed by upgrading
Yes

Solution

Upgrade python-multipart to version 0.0.26 or later.

Vulnerable code sample

import io

def vulnerable_read_preamble(stream: io.BytesIO, boundary: bytes):
    """
    This function simulates the vulnerable logic before the fix. It reads
    all data before the first boundary (the "preamble") into an in-memory
    buffer.

    If an attacker provides a request body with a very large preamble
    (e.g., 1 GB of newline characters), this function will attempt to
    buffer all of that data in RAM, leading to excessive memory
    consumption and a Denial of Service (DoS).
    """
    buffer = bytearray()
    boundary_line = b'--' + boundary

    while True:
        line = stream.readline()
        if not line:
            # End of stream reached without finding a boundary.
            break

        if line.startswith(boundary_line):
            # Boundary found. The preamble processing is complete.
            # A real parser would now handle this boundary line.
            break
        else:
            # VULNERABLE STEP: Append preamble line to the buffer.
            # There is no limit on the size of this buffer.
            buffer.extend(line)

    return buffer

Patched code sample

import sys

class FixedMultipartParser:
    """
    A conceptual parser demonstrating the fix for a DoS vulnerability
    caused by large preambles and epilogues in multipart data.
    """
    _STATE_PREAMBLE = 0
    _STATE_PART = 1
    _STATE_DONE = 2

    def __init__(self, boundary: bytes):
        self.boundary = b'--' + boundary
        self.final_boundary = self.boundary + b'--'
        self.state = self._STATE_PREAMBLE
        self._buffer = b''

    def feed_data(self, data: bytes):
        """
        Feeds data to the parser.

        The fix is demonstrated by:
        1.  Immediately stopping processing and discarding data if the final
            boundary has been seen (state is _STATE_DONE).
        2.  Efficiently searching for the first boundary instead of buffering
            or slowly processing the entire preamble.
        """
        # FIX 1: If parsing is finished, immediately discard any new data (epilogue).
        # A vulnerable parser would continue to buffer this, leading to DoS.
        if self.state == self._STATE_DONE:
            return

        self._buffer += data

        if self.state == self._STATE_PREAMBLE:
            # FIX 2: Efficiently find the first boundary and discard the preamble.
            # A vulnerable parser might process the preamble byte-by-byte, consuming
            # CPU and memory for large preambles.
            try:
                boundary_pos = self._buffer.index(self.boundary)
                # Discard the preamble before the boundary
                self._buffer = self._buffer[boundary_pos:]
                self.state = self._STATE_PART
            except ValueError:
                # To prevent unbounded buffer growth from a huge preamble without a
                # boundary, only keep a small tail of the buffer.
                tail_size = len(self.boundary) - 1
                if len(self._buffer) > tail_size:
                    self._buffer = self._buffer[-tail_size:]
                return

        if self.state == self._STATE_PART:
            # In a real parser, this would process headers and data between boundaries.
            # For this demonstration, we just look for the final boundary.
            try:
                final_boundary_pos = self._buffer.index(self.final_boundary)
                # Final boundary found. Stop processing.
                self.state = self._STATE_DONE
                # Discard all buffered data, including the final boundary itself.
                self._buffer = b''
            except ValueError:
                # Final boundary not yet in buffer. A real implementation would also
                # look for intermediate boundaries to yield completed parts.
                pass

Payload

(b'\r\n' * 10000000) + \
b'--boundary\r\n' \
b'Content-Disposition: form-data; name="field1"\r\n\r\n' \
b'value1\r\n' \
b'--boundary--\r\n'

Cite this entry

@misc{vaitp:cve202640347,
  title        = {{Python-Multipart DoS via large preamble/epilogue in multipart requests.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-40347},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-40347/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::