Read the docs
TI-2026-80021 Aliases GHSA-xmj3-9gf7-h52w

Windows path escape in setuptools legacy wheel installation

Priority LOW 38CWE-22Published · Updated

Key facts

Attack vector
—
Privileges required
—
User interaction
—
Attack complexity
—
Impact type
—
Confidentiality · integrity · availability
—
Fix status
Fixed

No CVSS vector from any source. Fix status from GitHub.

Summary

setuptools versions from 38.2.2 before 84.1.0 are affected. On Windows, setuptools' legacy wheel installation path trusts the namespace_packages.txt file inside a wheel's .dist-info directory, so a crafted wheel can make setuptools create an __init__.py file outside the requested destination directory (CWE-22). An attacker who supplies a wheel can influence where the file is written, but not its contents, and the file is written with the permissions of the process performing the installation.

Written with Claude Haiku 5.5 from the sources below · 2026-10-28

Description from the GitHub advisory

### Summary 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.

Why it matters now

Fix Fixed setuptools (PyPI): 84.1.0

SSVC decision points

Not available: CISA has not published SSVC decision points for this record.

Affected products

VendorProductAffected versionsFixed inStatusSource
—setuptools (PyPI)38.2.2 to before 84.1.084.1.0Patch availableGHSA-xmj3-9gf7-h52w
  • setuptools (PyPI) Vendor— Affected 38.2.2 to before 84.1.0 Fixed in 84.1.0 Patch available GHSA-xmj3-9gf7-h52w

Remediation

Upgrade setuptools to version 84.1.0 or later.

Written with Claude Haiku 5.5 from the sources below · 2026-10-28

  • Fix · GHSA-xmj3-9gf7-h52w setuptools (PyPI) Fixed in 84.1.0 Advisory →

Timeline

  1. 2026-10-23 Threatist record created from GHSA-xmj3-9gf7-h52w

References

Sources

This product uses the NVD API but is not endorsed or certified by the NVD. Sources and licences