VAITP Dataset

← Back to the dataset

CVE-2025-47273

Setuptools path traversal allows arbitrary file write, potentially RCE. Fix in 78.1.1.

  • CVSS 7.7
  • CWE-22
  • Input Validation and Sanitization
  • Remote

setuptools is a package that allows users to download, build, install, upgrade, and uninstall Python packages. A path traversal vulnerability in `PackageIndex` is present in setuptools prior to version 78.1.1. An attacker would be allowed to write files to arbitrary locations on the filesystem with the permissions of the process running the Python code, which could escalate to remote code execution depending on the context. Version 78.1.1 fixes the issue.

CVSS base score
7.7
Published
2025-05-17
OWASP
A01 Broken Access Control
Orthogonal defect classification
Interface
Code defect classification
Incorrect Functionality
Category
Input Validation and Sanitization
Subcategory
Path Traversal
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
setuptools
Fixed by upgrading
Yes

Solution

Upgrade to setuptools version 78.1.1 or higher.

Vulnerable code sample

import os
import zipfile

def extract_package(zip_file, destination_dir):
    """
    Extracts a package from a zip file to a specified destination directory.
    This function is intentionally vulnerable to path traversal.
    """
    with zipfile.ZipFile(zip_file, 'r') as zf:
        for member in zf.infolist():
            # Vulnerable code:  Does not properly sanitize the member.filename.
            # A malicious zip file could contain entries like "../../evil.txt" 
            # which would write outside of the intended destination_dir.
            filepath = os.path.join(destination_dir, member.filename)
            zf.extract(member, destination_dir)  #Extracts to filepath

            if __name__ == '__main__':
    # Example usage (demonstrates the potential vulnerability):
                zip_file = 'malicious_package.zip'  # Replace with an actual zip file.
                destination_dir = 'extracted_package'
                os.makedirs(destination_dir, exist_ok=True) #create the directory where the zip file will be extracted

    # Create a malicious zip file for demonstration purposes (avoid in production):
    # DO NOT CREATE THIS FILE IN A REAL ENVIRONMENT
                with zipfile.ZipFile(zip_file, 'w') as zf:
                    zf.writestr('../../evil.txt', 'This file should not be here!')
                    zf.writestr('good_file.txt', 'This is a legitimate file.')


                    try:
                        extract_package(zip_file, destination_dir)
                        print(f"Package extracted to {destination_dir}")
                        except Exception as e:
                            print(f"An error occurred: {e}")

    # After running, check if evil.txt was created outside of the:
    # extracted_package directory.  If so, the vulnerability is demonstrated.
                            if os.path.exists('../../evil.txt'):
                                print("VULNERABILITY DEMONSTRATED: evil.txt created outside of intended directory!")
                                os.remove('../../evil.txt')  # Clean up the malicious file.
                            else:
                                print("Vulnerability was not demonstrated.")

                                os.remove(zip_file) #delete the malicious zip file
                                import shutil
                                shutil.rmtree(destination_dir) #delete the extracted directory

                                ```

                                Explanation:

                                1.  **`extract_package(zip_file, destination_dir)` function:** This function is the core of the demonstration. It takes a zip file and a destination directory as input.  The vulnerability lies in how it constructs the full file path: `filepath = os.path.join(destination_dir, member.filename)`.  It directly concatenates the destination directory with the filename from the zip archive *without any sanitization*. This is the dangerous part.

                                2.  **Path Traversal:**  The `member.filename` can contain directory traversal sequences like `../` which will allow the code to write outside of the intended `destination_dir`.

                                3.  **Example Usage:**
                                *   It creates a directory `extracted_package` to simulate where the package would be extracted.
                                *   The crucial part is how it creates the `malicious_package.zip`.  It uses `zf.writestr('../../evil.txt', ...)` to create an entry in the zip file with a filename that includes path traversal (`../../`).  This filename is *designed* to write to the parent directory of the `extracted_package` directory.
                                *   Then calls the `extract_package` function.
                                *   Finally, it checks if `evil.txt` was actually created in the parent directory. If it was, the vulnerability is demonstrated.:
                                *   Includes cleanup code to remove the created files after execution.  It is extremely important to clean up, especially when dealing with potential security issues.

                                Important Considerations:

                                *   **Security:** This code is for demonstration purposes *only*.  **Do not use it in a production environment.**  It intentionally contains a security vulnerability.:
                                *   **Malicious Zip Files:**  Be extremely cautious when handling zip files from untrusted sources. They can contain malicious content designed to exploit vulnerabilities like this one.
                                *   **Mitigation:**  The fix for CVE-2025-47273 (in setuptools 78.1.1) would involve carefully sanitizing the `member.filename` to prevent path traversal.  This could include:
                                *   Checking if the path is absolute (e.g., starts with `/` on Linux/macOS or `C:\` on Windows).
                                *   Checking if the path contains `../` sequences.:
                                *   Using `os.path.normpath()` to normalize the path and remove redundant separators and up-level references.
                                *   Ensuring that the final extracted path is still within the intended destination directory.
                                *   **Real-World Impact:** In a real-world scenario, an attacker might be able to overwrite critical system files, inject malicious code into existing applications, or otherwise compromise the system.

                                This explanation provides a comprehensive overview of the vulnerability and how it can be demonstrated. Remember to always handle file paths carefully and sanitize them to prevent path traversal attacks.

Patched code sample

import os

def secure_filename(filename):
    """
    Sanitizes a filename to prevent path traversal vulnerabilities.
    """
    # Split the filename into components based on the OS's path separator.
    parts = filename.split(os.path.sep)

    # Filter out any empty parts, ".", "..", and absolute paths.
    safe_parts = [
        part for part in parts
        if part and part not in (".", "..") and not os.path.isabs(part)
    ]

    # Join the safe parts back together.
    return os.path.join(*safe_parts)


def write_file(destination_directory, filename, content):
    """
    Writes content to a file in a specified directory, ensuring path safety.
    """
    safe_filename = secure_filename(filename)

    # Check if the filename is safe after sanitization.  If it's empty, it means
    # the filename only contained unsafe characters.
    if not safe_filename:
        raise ValueError("Filename contains only unsafe characters.")

    # Construct the full path to the file.
    full_path = os.path.join(destination_directory, safe_filename)

    # Create the destination directory if it doesn't exist.
    os.makedirs(destination_directory, exist_ok=True)

    # Write the content to the file.
    with open(full_path, "w") as f:
        f.write(content)

# Example Usage (safe)
#destination_dir = "/tmp/safe_directory"
#filename = "harmless.txt"
#content = "This is some safe content."

#try:
#    write_file(destination_dir, filename, content)
#    print("File written successfully.")
#except ValueError as e:
#    print(f"Error: {e}")


# Example Usage (attempted path traversal - WILL RAISE ERROR)
#destination_dir = "/tmp/safe_directory"
#filename = "../../../../../../../evil.txt"  # Attempt to traverse outside the intended directory
#content = "This is malicious content."

#try:
#    write_file(destination_dir, filename, content)
#    print("File written successfully.")
#except ValueError as e:
#    print(f"Error: {e}")  # This will be printed because secure_filename returns ""

Payload

../../../../../../../../tmp/evil.py

Cite this entry

@misc{vaitp:cve202547273,
  title        = {{Setuptools path traversal allows arbitrary file write, potentially RCE. Fix in 78.1.1.
}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-47273},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-47273/}}
}
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 ::