Skip to main content
← All vulnerabilities
GHSA-XMJ3-9GF7-H52W

setuptools: Windows path escape via namespace_packages.txt during legacy wheel installation Description

Published
Last modified
published
Not listed in CISA KEV
Low (ghsa)
Fix
Fixed in 84.1.0
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

  1. Advisory published
  2. Record last updated
  3. First seen by cve.now

Affected versions

  • setuptoolsPyPI

    From 38.2.2 · fixed in 84.1.0

References 5

GitHub · pypa/setuptools