When installing dependencies, Python package managers like pip will automatically execute build scripts distributed along with the source code. The most common build script is setup.py, which runs arbitrary Python code during installation. Build scripts are a common way to execute malicious code at install time whenever a package is compromised. The modern approach is to use pyproject.toml instead, which does not execute arbitrary code during installation.

Why is this an issue?

When package managers execute installation scripts, they run arbitrary code distributed with third-party packages. A compromised package can use this mechanism to execute malicious code on the build system, potentially stealing credentials, injecting backdoors, or otherwise compromising the supply chain.

What is the potential impact?

If a dependency is compromised and its scripts are executed, an attacker can run arbitrary code with the permissions of the process performing the installation. This can lead to credential theft from the build environment, introduction of backdoors into the application, or lateral movement within CI/CD infrastructure.

How to fix it in pip

Code examples

Noncompliant code example

FROM python:latest

COPY requirements.txt .
RUN pip install -r requirements.txt  # Noncompliant

Compliant solution

FROM python:latest

COPY requirements.txt .
RUN pip install --only-binary :all: -r requirements.txt

How to fix it in Poetry

Code examples

Noncompliant code example

FROM python:latest

RUN poetry install  # Noncompliant

Compliant solution

FROM python:latest

RUN POETRY_INSTALLER_ONLY_BINARY=:all: poetry install

How to fix it in uv

Code examples

Noncompliant code example

FROM python:latest

COPY requirements.txt .
RUN uv pip install -r requirements.txt  # Noncompliant
FROM python:latest

RUN uv sync  # Noncompliant
FROM python:latest

RUN uv run script.py  # Noncompliant
FROM python:latest

RUN uv tool run pkg  # Noncompliant

Compliant solution

FROM python:latest

COPY requirements.txt .
RUN uv pip install --no-build -r requirements.txt
FROM python:latest

RUN uv sync --no-build
FROM python:latest

RUN uv run --no-build script.py
FROM python:latest

RUN uv tool run --no-build pkg

Resources

Standards