uv/crates/uv-extract
Charlie Marsh 2677e85df9
Disallow writing symlinks outside the source distribution target directory (#12259)
## Summary

Closes #12163.

## Test Plan

Created an offending source distribution with this script:

```python
import io
import tarfile
import textwrap
import time

PKG_NAME  = "badpkg"
VERSION   = "0.1"
DIST_NAME = f"{PKG_NAME}-{VERSION}"
ARCHIVE   = f"{DIST_NAME}.tar.gz"


def _bytes(data: str) -> io.BytesIO:
    """Helper: wrap a text blob as a BytesIO for tarfile.addfile()."""
    return io.BytesIO(data.encode())


def main(out_path: str = ARCHIVE) -> None:
    now = int(time.time())

    with tarfile.open(out_path, mode="w:gz") as tar:

        def add_file(path: str, data: str, mode: int = 0o644) -> None:
            """Add a regular file whose *content* is supplied as a string."""
            buf  = _bytes(data)
            info = tarfile.TarInfo(path)
            info.size   = len(buf.getbuffer())
            info.mtime  = now
            info.mode   = mode
            tar.addfile(info, buf)

        # ── top‑level setup.py ───────────────────────────────────────────────
        setup_py = textwrap.dedent(f"""\
            from setuptools import setup, find_packages
            setup(
                name="{PKG_NAME}",
                version="{VERSION}",
                packages=find_packages(),
            )
        """)
        add_file(f"{DIST_NAME}/setup.py", setup_py)

        # ── minimal package code ─────────────────────────────────────────────
        add_file(f"{DIST_NAME}/{PKG_NAME}/__init__.py", "# placeholder\\n")

        # ── the malicious symlink ────────────────────────────────────────────
        link = tarfile.TarInfo(f"{DIST_NAME}/{PKG_NAME}/evil_link")
        link.type     = tarfile.SYMTYPE
        link.mtime    = now
        link.mode     = 0o777
        link.linkname = "../../../outside.txt"
        tar.addfile(link)

    print(f"Created {out_path}")


if __name__ == "__main__":
    main()
```

Verified that both `pip install` and `uv pip install` rejected it.

I also changed `link.linkname = "../../../outside.txt"` to
`link.linkname = "/etc/outside"`, and verified that the absolute path
was rejected too.
2025-07-22 09:20:09 -04:00
..
src Disallow writing symlinks outside the source distribution target directory (#12259) 2025-07-22 09:20:09 -04:00
Cargo.toml Move static feature out of perf features (#13265) 2025-05-02 15:56:40 +00:00