Skip to content

[Bug]: salt-pip does not isolate the pip subprocess's PYTHONPATH, which can cause it to uninstall unrelated system packages #70151

Description

@twangboy

What happened?

salt-pip is meant to be a self-contained wrapper around the onedir's bundled pip: packages it installs go into an isolated extras-. directory alongside the onedir, kept separate from the system Python (see doc/topics/packaging/index.rst). In practice, that isolation is incomplete.

_pip_environment() in salt/scripts.py builds the environment for the pip subprocess like this:

def _pip_environment(env, extras):
    new_env = env.copy()
    if "PYTHONPATH" in env:
        new_env["PYTHONPATH"] = f"{extras}{os.pathsep}{env['PYTHONPATH']}"
    else:
        new_env["PYTHONPATH"] = extras
    return new_env

Rather than isolating the subprocess, it prepends salt's own extras directory onto whatever PYTHONPATH was already present in the calling process's environment. If anything invoking salt-pip — a shell session, an init/systemd unit, a packaging post-install hook, a CI job, etc. — has a PYTHONPATH set (intentionally or via leakage from unrelated tooling), that path is carried straight through into salt's supposedly isolated Python subprocess.

Why this is a problem

PYTHONPATH entries are visible to whichever interpreter is running, regardless of which Python installation they actually belong to — a pure-Python package sitting in an unrelated Python 3.x installation's site-packages is just as importable from salt's bundled/relenv interpreter as one installed properly inside extras.

This becomes actively destructive with --force-reinstall: pip's install logic uninstalls whatever it finds "already satisfying" a given requirement anywhere on sys.path, not just inside the directory it's about to install into. So salt-pip install --force-reinstall <pkg> can end up deleting a same-named package belonging to a completely unrelated Python environment — the host's system Python, or some other application's separate Python stack — if that environment happens to be exposed via an inherited PYTHONPATH. That's a package the user never asked salt-pip to touch, disappearing from a Python installation salt-pip has no business modifying, potentially breaking whatever depended on it.

Impact

Observed in the field: a PYTHONPATH leaked into the environment from an unrelated build/init process caused salt-pip install --force-reinstall to delete a package belonging to a separate, unrelated Python 3.x application stack on the same host, breaking that application.

Expected behavior

salt-pip's subprocess environment should be genuinely isolated, as documented: it should only ever expose its own managed extras directory on PYTHONPATH, never merge in anything inherited from the calling process's environment.

Type of salt install

Official deb

Major version

3006.x

What supported OS are you seeing the problem on? Can select multiple. (If bug appears on an unsupported OS, please open a GitHub Discussion instead)

debian-11

salt --versions-report output

3006.x

Metadata

Metadata

Assignees

Labels

bugbroken, incorrect, or confusing behavior

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions