In November 2014, the Python packaging authority disclosed a bug in pip that allowed any local user to block package installations for everyone else on the same machine. The flaw, tracked as CVE-2014-8991, affected pip versions 1.3 through 1.5.6 and stemmed from the use of predictable temporary build directory names under /tmp. While the fix shipped with pip 6.0 later that year, the bug persists in forgotten containers, frozen virtual machines, and legacy CI environments, potentially disrupting software builds and deployments even today.

The Predictably Broken Build Directory

At its core, CVE-2014-8991 is a classic temporary-file design mistake. When building packages from source, older pip releases created a build directory in the system’s temporary folder using a predictable pattern: /tmp/pip-build-<project>. The logic checked for existence and, if the path was free, used it for unpacking and compilation. An attacker with local file-system access could simply create a file or directory with that exact name beforehand. When another user ran pip for the same project, pip would encounter the pre‑existing object and fail — unable to write build artifacts or unpack source tarballs.

No privilege escalation or remote code execution is involved. The attack is purely a local denial‑of‑service (DoS): a single unprivileged user can prevent pip from installing or upgrading packages for any other user on the same host. Yet the operational impact can ripple far beyond a single failed command.

The affected versions are tightly scoped:

pip Version Range Vulnerability Status
1.3 – 1.5.6 Vulnerable
6.0 and later Fixed

pip 1.3 was released in April 2013; 1.5.6 saw its final release in May 2014. By the time the bug was publicly disclosed, pip 1.5.6 had been the latest stable version for months, meaning the vulnerability was present in virtually every Python environment that had not yet adopted development snapshots.

Why You Should Care — Even on Windows

On a single‑user Windows desktop, an attacker would need to be seated at your keyboard to exploit this. But in the real world, Python and pip thrive in shared, multi‑tenant environments where multiple accounts — or containerized processes — share a common temperature space. These are precisely the places where stale pip versions tend to hide.

Shared Windows servers and build farms. A Windows Server with Remote Desktop Services, a lab machine shared by a dozen developers, or a continuous integration (CI) runner that executes jobs from different teams all present the same risk: any authenticated user can sabotage Python‑based build steps for everyone else. A disgruntled insider or a compromised low‑privilege account can flood /tmp (or %TEMP% on native Windows if pip uses a predictable folder there) with rogue directories, turning a developer’s routine pip install into a mysterious failure.

Windows Subsystem for Linux (WSL) and Docker. Many Windows‑based developers run Python inside WSL distributions or Linux containers. In a WSL2 instance, /tmp is typically isolated from the host, but if multiple users share the same WSL environment — or if container images built years ago are still pulled from a registry — the vulnerability can resurface. A Jenkins agent running on Windows that spins up Python‑based build containers might find itself blocked by a malicious actor inside the container or on the shared volume.

Legacy Windows deployments of Python. Although native Windows Python installations are less common on multi‑user machines, they do exist. Systems administrators sometimes deploy Python with pip via enterprise software distribution. If those deployments pinned an ancient pip version (1.3–1.5.6) and the machine later becomes shared, the bug awaits.

The CVSS v2 base score of 2.1 reflects the local attack vector and limited impact — but security practitioners know that severity depends on context. A local DoS on a single‑user laptop matters little; on a CI server that cranks out 200 builds a day, every minute of downtime cascades into missed release windows and frustrated engineers.

How the Fix Works and Why It Took Hold

pip’s upstream developers addressed CVE-2014-8991 with a principled overhaul. The core change, introduced in pip 6.0, replaces the predictable /tmp/pip-build-* naming with randomized, secure temporary directories. When possible, pip now uses Python’s tempfile.mkdtemp() equivalent, which creates a uniquely‑named directory atomically and avoids the time‑of‑check‑to‑time‑of‑use (TOCTOU) race condition that made the old behavior exploitable.

Additionally, pip now respects the standard environment variables TMPDIR, TEMP, and TMP, allowing administrators to redirect build directories to per‑user or per‑job locations. The build directory can also be set explicitly with the --build-dir option or configured in pip.conf, giving operators fine‑grained control.

The fix is referenced in pip’s repository as pull request #2122 and appears in the changelog for version 6.0. Major Linux distributions and the Python Package Authority backported the patch into their respective package streams. But while the upstream fix was clean and timely, its propagation through the ecosystem has been far from uniform.

The Long Tail of Legacy Vulnerabilities

CVE-2014-8991 illustrates why even “low‑severity” bugs can have a surprisingly long half‑life. The vulnerability is not present in any modern pip release; the current pip 24.x (as of 2025) is immune. Yet the bug lingers wherever old software stacks go unmaintained:

  • Golden images and frozen containers. IT organizations often freeze an OS image with a specific Python environment to ensure reproducibility. Those images may contain pip 1.5.6 if they were born around 2014. When deployed into a multi‑user setting — think of a shared development VM or a Kubernetes node where multiple pods share a host’s /tmp — the old vulnerability becomes live again.
  • Embedded systems and appliances. Network‑attached storage devices, industrial controllers, and other appliances sometimes run Python internally and may include an ancient pip for factory provisioning. A local user on the device (or an attacker who gains limited shell access) could leverage the bug.
  • Unpatched enterprise distributions. Some long‑term‑support (LTS) Linux releases pinned pip to older versions for stability. While most have since updated, unsupported or poorly‑maintained installations may still be vulnerable. On the Windows side, enterprise software bundles that package Python seldom push frequent pip upgrades.

The discrepancy in severity scores across databases — CVSS v2 gave it 2.1, while some v3 refinements rate it higher — underscores a key lesson: a flaw’s real‑world danger is a function of how software is deployed, not just its technical classification. In multi‑tenant environments, a local availability problem is an availability problem for the whole service.

A Checklist to Lock Down Your pip Environment

Remediation is straightforward, but you need to know where to look. Use this prioritized plan to root out vulnerable pip installations in your fleet.

1. Inventory: Find Old pip Versions

Scan all systems where pip might be hiding — development VMs, CI workers, container images, and golden OS templates. Run these commands on Linux (including WSL) and macOS; on native Windows, use python -m pip --version or check the installed program list.

pip --version
python -m pip --version  # if pip is invoked via the module
dpkg -l python-pip       # Debian/Ubuntu
rpm -q python-pip        # RHEL/CentOS

Any output showing a version between 1.3 and 1.5.6 demands immediate attention. Also check automation scripts, virtual environments, and CI job definitions that might install a specific, outdated pip version.

2. Upgrade pip Everywhere

Upgrading is the silver bullet. For most systems, a simple command suffices:

python -m pip install --upgrade pip

For system‑wide installations managed by a package manager, prefer the OS update channel:

sudo apt update && sudo apt upgrade python-pip   # Debian/Ubuntu
sudo yum update python-pip                       # RHEL/CentOS 7
sudo dnf upgrade python-pip                      # Fedora/RHEL 8+

If you maintain Windows native Python installations, download the latest Python installer and tick “Upgrade pip” during setup, or run the same --upgrade pip command in an elevated Command Prompt.

After upgrading, verify the new version (6.0 or higher) and confirm that the build directory behavior has changed. You can test by inspecting where pip places temporary builds:

pip --cache-dir /tmp/pip-temp-test install --no-deps some-package

The randomly‑named directory should appear under the cache location, not a fixed prefix.

3. Rebuild Container and VM Images

Stale images are the biggest source of residual risk. For each base image you maintain, check the pip version and rebuild if it’s outdated. If you cannot rebuild immediately, modify Dockerfiles to upgrade pip early in the build:

FROM python:3.7-slim  # example legacy image
RUN python -m pip install --upgrade pip==24.0

Container registries can be scanned with tools like Trivy or Snyk to identify images containing old pip versions.

4. Harden the Build Environment

Even with a modern pip, defense‑in‑depth reduces the chance of future temp‑file attacks:

  • Isolate build directories: Set TMPDIR to a per‑job or per‑user location in CI scripts. For example, export TMPDIR=$HOME/tmp ensures each user’s builds stay private.
  • Use virtual environments: Always run pip inside a venv or virtualenv; these tools often redirect temporary files to the environment directory instead of a global /tmp.
  • Employ --no-cache-dir or --build-dir: In sensitive contexts, you can force pip to use a custom, disposable build directory or skip caching entirely.

5. Monitor for Rogue Artifacts

Detection focuses on the file system. In shared /tmp directories, look for unexpected items matching pip-build-*. A simple audit script can alert on their presence:

find /tmp -name 'pip-build-*' -print

Correlate such files with failed pip invocations in job logs. If you consistently see “Could not install packages due to an EnvironmentError” or permission errors during build, and a suspicious file exists in /tmp, you’ve likely found the culprit.

Vigilance Against Predictable Temp Files Remains a Timeless Security Practice

CVE-2014-8991 is not a headline‑grabbing remote exploit, but it serves as a persistent reminder: software supply chains are only as strong as the oldest component in the stack. The fix is simple, cheap, and has been available for over a decade. The only reason this bug still threatens productivity is that we forget to check the depths of our infrastructure.

For platform engineers and IT administrators, the takeaway is clear. Treat every local DoS vulnerability in shared infrastructure as an imminent availability risk. Bake pip upgrade steps into image hardening baselines. And when you audit a system, look at the actual runtime environment — not just the shiny CI configuration — because that’s where the decade‑old pip binary is quietly waiting to trip someone up.