Severity by source
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
AC:H reflects the non-default deployment pattern required; A:L captures memory pressure rather than full service loss; C:N and I:N because no data is disclosed or modified.
Primary rating from Vendor (https://github.com/Kludex/python-multipart).
CVSS VectorVendor: https://github.com/Kludex/python-multipart
Lifecycle Timeline
2Blast Radius
ecosystem impact- 17 pypi packages depend on python-multipart (13 direct, 4 indirect)
Ecosystem-wide dependent count for version 0.0.31.
DescriptionCVE.org
Summary
parse_form() did not validate the Content-Length header before using it to bound its chunked read of the request body. A negative Content-Length turned the bounded read into a read-until-EOF, so the entire body was loaded into memory in a single read instead of in fixed-size chunks.
Details
parse_form() reads the input stream in chunks, never reading more than the remaining Content-Length at a time. The per-chunk size is computed as min(content_length - bytes_read, chunk_size). The header value was parsed to an integer without checking its sign, so a Content-Length of -1 made this expression negative, and input_stream.read(-1) reads until end of stream. The intended bounded, chunked read therefore collapsed into a single unbounded read of the whole stream. The amount read is still bounded by what the client actually sends.
Impact
This only affects code that calls parse_form() directly with a Content-Length header taken from attacker-controlled input and without normalizing a negative value first. No known package is affected:
- Starlette and FastAPI drive
MultipartParserdirectly from the ASGIreceive()stream and do not callparse_form(). - Known
parse_form()consumers either do not forwardContent-Lengthto it, recompute it from the already-read body, or run behind a layer (such as Werkzeug) that normalizes a negativeContent-Lengthto0.
The realistic exposure is limited to bespoke WSGI or http.server handlers that forward raw client headers into parse_form(). In that case a crafted request buffers the body in memory at once, degrading availability under concurrent requests rather than causing a complete denial of service.
Mitigation
Upgrade to version 0.0.31 or later, which rejects a negative Content-Length with a ValueError before reading the stream.
AnalysisAI
Memory exhaustion in python-multipart's parse_form() function allows a remote attacker to force unbounded body buffering by supplying a negative Content-Length header, degrading server availability under concurrent load. Affected deployments are narrowly scoped: only bespoke WSGI or http.server handlers that pass raw, unvalidated client-supplied Content-Length values directly into parse_form(). Mainstream consumers such as Starlette, FastAPI, and Werkzeug are not affected. No public exploit code exists and this vulnerability is not listed in the CISA KEV catalog, consistent with the low CVSS base score of 3.7.
Technical ContextAI
python-multipart (pkg:pip/python-multipart) provides multipart form-data and URL-encoded body parsing for Python web applications. The parse_form() function implements a chunked read loop bounded by the Content-Length header: each chunk size is computed as min(content_length - bytes_read, chunk_size). The integer parsed from the Content-Length header was never validated for sign, so a value of -1 makes the expression negative on the first iteration. Python's io.RawIOBase.read() interprets a negative argument as 'read until EOF', collapsing the intended bounded chunked loop into a single unbounded read of the entire request body into memory. The root cause maps to CWE-1284 (Improper Validation of Specified Quantity in Input): the quantity used to bound I/O was accepted without sign checking. The total bytes read is still limited by what the client actually transmits, so this is a memory pressure issue rather than an infinite loop.
RemediationAI
Upgrade python-multipart to version 0.0.31 or later, which rejects a negative Content-Length with a ValueError before any stream read occurs; this is the definitive fix per the vendor advisory at https://github.com/Kludex/python-multipart/security/advisories/GHSA-v9pg-7xvm-68hf. If an immediate upgrade is not feasible, the specific compensating control is to validate and normalize the Content-Length header before passing it to parse_form(): reject or clamp any value less than zero to 0 at the application or middleware layer. This can be implemented as a one-line guard (e.g., content_length = max(0, int(request.headers.get('Content-Length', 0)))) in the handler that calls parse_form(). A secondary control is to enforce server-side request body size limits at the reverse proxy or WSGI server level (e.g., LimitRequestBody in Apache, client_max_body_size in nginx), which caps the memory consumed per request regardless of the header value. The trade-off of the proxy limit approach is that it does not fix the root cause and may reject legitimate large uploads.
Same technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-38325
GHSA-v9pg-7xvm-68hf