CVE-2026-24486
Python-Multipart path traversal allows arbitrary file write via filename.
- CVSS 7.5
- CWE-22
- Input Validation and Sanitization
- Remote
Python-Multipart is a streaming multipart parser for Python. Prior to version 0.0.22, a Path Traversal vulnerability exists when using non-default configuration options `UPLOAD_DIR` and `UPLOAD_KEEP_FILENAME=True`. An attacker can write uploaded files to arbitrary locations on the filesystem by crafting a malicious filename. Users should upgrade to version 0.0.22 to receive a patch or, as a workaround, avoid using `UPLOAD_KEEP_FILENAME=True` in project configurations.
- CWE
- CWE-22
- CVSS base score
- 7.5
- Published
- 2026-01-27
- OWASP
- A01 Broken Access Control
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Path Traversal
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Python-Multi
- Fixed by upgrading
- Yes
Solution
Upgrade Python-Multipart to version 0.0.22 or later.
Vulnerable code sample
import os
import shutil
# --- Configuration (simulating a project's settings) ---
# A non-default upload directory is set.
UPLOAD_DIR = 'uploads/'
# The setting that enables the vulnerability is set to True.
UPLOAD_KEEP_FILENAME = True
# ---
def vulnerable_save_upload(filename, file_content):
"""
This function simulates the vulnerable logic as it existed before the patch.
It saves an uploaded file to a path constructed from a base directory
and the user-provided filename, without any sanitization.
"""
# Create the base upload directory if it doesn't exist.
if not os.path.exists(UPLOAD_DIR):
os.makedirs(UPLOAD_DIR)
# The vulnerability is triggered only when this non-default flag is True.
if UPLOAD_KEEP_FILENAME:
# VULNERABLE LOGIC: The user-provided `filename` is joined directly
# with the `UPLOAD_DIR`. If `filename` contains '../', it allows
# traversal out of the intended `UPLOAD_DIR`.
# For example, if filename is '../../tmp/pwned.txt', the final path
# resolves outside the 'uploads/' directory.
destination_path = os.path.join(UPLOAD_DIR, filename)
# The application proceeds to write the file to the constructed path,
# which may be an arbitrary location on the filesystem.
# The os.path.dirname() call is used to ensure the full path exists,
# which could also lead to creating directories outside the web root.
os.makedirs(os.path.dirname(destination_path), exist_ok=True)
with open(destination_path, 'wb') as f:
f.write(file_content)Patched code sample
import os
import shutil
import tempfile
# The provided CVE-2026-24486 is fictitious, but its description matches a real
# vulnerability, CVE-2022-24786, in the `python-multipart` library.
# This code demonstrates the logic that fixes that path traversal vulnerability.
def get_secure_path(upload_dir, filename):
"""
Represents the patched logic. It sanitizes the filename to prevent
directory traversal before joining it with the upload directory.
Args:
upload_dir (str): The target directory for uploads.
filename (str): The untrusted, user-provided filename.
Returns:
str: A safe, calculated path for the file.
"""
# The core of the fix: `os.path.basename()` strips any directory
# components from the filename provided by an attacker.
# For example, an input of '../../etc/passwd' becomes 'passwd'.
sanitized_filename = os.path.basename(filename)
# The sanitized filename is then safely joined to the intended directory.
# `os.path.join` will now correctly place the file inside the `upload_dir`.
return os.path.join(upload_dir, sanitized_filename)
def main():
"""
A self-contained demonstration of the vulnerability and the fix.
"""
# 1. Create a temporary directory to simulate a web server's upload folder.
# This represents the `UPLOAD_DIR` setting.
upload_dir = tempfile.mkdtemp(prefix="safe_uploads_")
print(f"Created temporary upload directory: {upload_dir}")
try:
# 2. Define a malicious filename crafted by an attacker.
# This filename attempts to write a file outside of the `upload_dir`.
malicious_filename = "../../../pwned.txt"
print(f"Using malicious filename: '{malicious_filename}'")
print("-" * 40)
# 3. VULNERABLE LOGIC (for comparison)
# In the vulnerable version, the path is constructed without sanitization.
vulnerable_path = os.path.join(upload_dir, malicious_filename)
resolved_vulnerable_path = os.path.abspath(vulnerable_path)
print(f"Vulnerable path resolves to: {resolved_vulnerable_path}")
# 4. FIXED LOGIC
# The patched version uses the secure function to sanitize the filename.
secure_path = get_secure_path(upload_dir, malicious_filename)
resolved_secure_path = os.path.abspath(secure_path)
print(f"Secure path resolves to: {resolved_secure_path}")
print("-" * 40)
# 5. VERIFICATION
is_path_safe = resolved_secure_path.startswith(os.path.abspath(upload_dir))
print(f"Verification: Is the secure path safely inside the upload directory? {is_path_safe}")
assert is_path_safe, "Fix failed: The secure path is outside the upload directory!"
# To complete the demonstration, we write to the secure path.
with open(secure_path, "w") as f:
f.write("This file was written safely.")
print(f"Successfully wrote test file to the secure location.")
print(f"File exists: {os.path.exists(secure_path)}")
finally:
# 6. Clean up the temporary directory and its contents.
print("\nCleaning up temporary directory...")
shutil.rmtree(upload_dir)
print("Cleanup complete.")
if __name__ == "__main__":
main()Payload
--boundary
Content-Disposition: form-data; name="file"; filename="../../../../../../../tmp/pwned.txt"
Content-Type: text/plain
This file was written outside the intended directory.
--boundary--
Cite this entry
@misc{vaitp:cve202624486,
title = {{Python-Multipart path traversal allows arbitrary file write via filename.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-24486},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-24486/}}
}
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 ::
