GHSA-xmj3-9gf7-h52w: Path Traversal
Summary
On Windows, attacker-controlled content in a wheel's .dist-info/namespacepackages.txt can cause setuptools' legacy wheel installation path to create an init.py outside the requested destinationeggdir.
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(wheelpath).installasegg(destination) → installasegg → convertmetadata → fixnamespacepackages
A wheel can provide attacker-controlled content in:
<distribution>.dist-info/namespacepackages.txt
The namespace value is eventually used approximately as:
python moddir = os.path.join(destinationeggdir, mod.split('.')) modinit = os.path.join(moddir, '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(destinationeggdir, absolutecomponent) 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:
demopkg-1.0.dist-info/namespacepackages.txt
whose content was the absolute path of:
sandbox\outside
The real acquired setuptools implementation was then invoked:
python setuptools.wheel.Wheel(syntheticwheel).installasegg( sandboxdestination )
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('pkgresources').declarenamespace(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.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/setuptoolsto a version that resolves this vulnerability.Fixed in 84.1.0