setuptools: Windows path escape via namespace_packages.txt during legacy wheel installation Description
- Published
- Last modified
- Where the record stands: published, rejected by its publisher, or superseded by another id.What do these mean? →
- published
- Whether CISA lists it in its Known Exploited Vulnerabilities catalog: proof that attackers are using it.What do these mean? →
- Not listed in CISA KEV
- The rating the maker of the software gives it. Shown when it differs from the CVSS level.What do these mean? →
- Low (ghsa)
- Fix
- Fixed in 84.1.0
- Whether working attack code is public (Exploit-DB, Metasploit, Nuclei or GitHub). Public code makes attacks easier.What do these mean? →
- None on Exploit-DB, Metasploit or GitHub
Summary
This vulnerability affects setuptools, the Python packaging library, specifically its legacy wheel installation code on Windows. An attacker who supplies a malicious wheel file can cause setuptools to create an `__init__.py` file outside the intended installation directory.
Summarized by anthropic/claude-haiku-5.5. Verify details against the original sources.
Read the original description
On Windows, attacker-controlled content in a wheel's `.dist-info/namespace_packages.txt` can cause setuptools' legacy wheel installation path to create an `init.py` outside the requested `destination_eggdir`. The attacker can influence the destination path, but not the contents of the created file. Details Tested setuptools commit: `6ead555c5fb29bc57fe6105b1bffc163f56fd558` Relevant source: `setuptools/wheel.py` SHA-256: `359b7e0d5dd8c3135653abe08a8ed5dc0352eadfd7df22cb5e2b5303b7c3cafd` The relevant call path is: `Wheel(wheel_path).install_as_egg(destination)` → `_install_as_egg` → `_convert_metadata` → `_fix_namespace_packages` A wheel can provide attacker-controlled content in: `<distribution>.dist-info/namespace_packages.txt` The namespace value is eventually used approximately as: ```python mod_dir = os.path.join(destination_eggdir, *mod.split('.')) mod_init = os.path.join(mod_dir, 'init.py') If mod is a Windows drive-qualified absolute path containing no dots, mod.split('.') preserves it as a single component. On Windows, os.path.join(destination_eggdir, absolute_component) discards the original base directory and resolves to the attacker-supplied absolute path. The existing wheel filename and ZIP traversal checks do not validate this metadata value before it is subsequently interpreted as a filesystem path. ```markdown PoC The reproduction was performed entirely inside a disposable temporary directory. Layout: ```text sandbox/ destination/ outside/ input/ canary.txt ``` A synthetic wheel was created containing: `demo_pkg-1.0.dist-info/namespace_packages.txt` whose content was the absolute path of: `sandbox\outside` The real acquired setuptools implementation was then invoked: ```python setuptools.wheel.Wheel(synthetic_wheel).install_as_egg( sandbox_destination ) ``` The operation completed without exception. Expected metadata was created under: `sandbox\destination\EGG-INFO` but setuptools also created: `sandbox\outside\init.py` The file did not exist before execution. Its contents were: ```python import('pkg_resources').declare_namespace(name) ``` The unrelated canary remained byte-identical. The sandbox was deleted after recording the evidence. ``` Impact A crafted wheel can cause setuptools to create a fixed-content `init.py` outside the intended installation directory at a filesystem path influenced by the wheel, with the permissions of the process performing the installation. The demonstrated reproduction required the target parent directory to already exist.
Timeline
- Advisory published
- Record last updated
- First seen by cve.now
Affected versions
- setuptoolsPyPI
From 38.2.2 · fixed in 84.1.0