python-multipart: Content-Disposition parameter smuggling via RFC 2231/5987 extended parametersGHSA-vffw-93wf-4j4q
LOWGHSA-vffw-93wf-4j4q is a low-severity (CVSS 3.7) Improper Input Validation vulnerability in python-multipart. A fix is available for python-multipart — see the affected versions and patch details below.
Exploitation Status
No confirmed exploitation observed yet
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for GHSA-vffw-93wf-4j4q.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
GHSA-vffw-93wf-4j4q by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 394,803 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
python-multipartReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
parse_options_header parsed Content-Disposition (and Content-Type) headers with email.message.Message, which transparently applies RFC 2231/5987 decoding. The extended parameter syntax (filename*=charset'lang'value, name*=..., and the filename*0/filename*1 continuation form) is decoded and surfaced under the bare filename/name key, and overrides the plain parameter when both are present. RFC 7578 §4.2 explicitly forbids the filename* form in multipart/form-data.
Components that follow RFC 7578, or that do not implement RFC 2231/5987 decoding for multipart/form-data (WAFs, proxies, gateways), may interpret such a header differently. An attacker can exploit that difference to smuggle a different field name or filename past an upstream inspector to the backend.
Details
Given both a plain and an extended parameter, the extended value won. For example:
Content-Disposition: form-data; name="comment"; name*=utf-8''role
An inspector following RFC 7578 sees the field comment, while the returned value was name=role. The same applies to filenames:
Content-Disposition: form-data; name="upload"; filename="safe.txt"; filename*=utf-8''evil.php
The inspector sees safe.txt, while the returned value was filename=evil.php. Continuation parameters (filename*0, filename*1, and so on) were likewise reassembled into a filename invisible to a plain filename= match, and percent encoded sequences in the extended value were decoded (so ..%2F, %00, and similar appeared in the returned filename).
This affects the high level parse_options_header, FormParser, create_form_parser, and parse_form APIs, and reaches Starlette/FastAPI through request.form(), where the smuggled value is exposed as the form field name or UploadFile.filename.
Impact
This is an interpretation conflict (CWE-436) with other multipart/form-data parsers. An attacker able to submit multipart/form-data can present a different field name or filename to an upstream body inspecting component than the one delivered to the application. Concrete consequences depend on how the application uses these values, and may include bypassing a field name or filename based access/upload control, or, for an application that builds filesystem paths from the parsed filename without sanitization, path traversal via decoded ..%2F sequences. Decoded control bytes such as %00 can likewise cause confusion between an upstream validator and the backend. The File class applies os.path.basename, so file writing through it is not directly affected.
Mitigation
Upgrade to python-multipart 0.0.30 or later, which ignores RFC 2231/5987 extended parameters (name*, filename*, and their continuations) so the plain name/filename parameter remains authoritative. RFC 7578 §4.2 forbids filename* for multipart/form-data; name* and the continuation forms are dropped for the same reason, since they are not valid multipart/form-data parameters either.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | python-multipart | all versions | 0.0.30pip install --upgrade 'python-multipart==0.0.30' |
Affected Products
python-multipartfastapiexpertDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for python-multipart, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update python-multipart to 0.0.30 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-vffw-93wf-4j4q is resolved across your whole dependency graph.
Workarounds
Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.
Frequently Asked Questions
Is GHSA-vffw-93wf-4j4q in your dependencies?
Find it across PyPI, including transitive dependencies.