When your team runs pip install, you're not just downloading a library. You're allowing arbitrary code to execute on your infrastructure, often with the same privileges as your build pipeline or production environment. For those managing software supply chain risk, that single command represents a trust boundary with almost no visibility.
The Python Package Index (PyPI) hosts over 500,000 packages, and unlike curated app stores, there's no pre-publication security review. Any developer can publish, and any package can execute setup scripts. Your organization's attack surface grows with every dependency.
What Happens During Installation
Between the moment pip contacts PyPI and when your application imports a module, eight distinct execution opportunities exist:
1. Package resolution and download
Pip queries PyPI's JSON API, which returns metadata including dependencies, version constraints, and download URLs. A compromised PyPI mirror or DNS hijack at this stage can redirect your installer to malicious packages. The installer trusts whatever the index returns.
2. Setup script execution
If a package includes a setup.py file, pip executes it with your current user privileges. This script can read environment variables, scan your filesystem, exfiltrate credentials, or install backdoors before you ever import the library. There's no sandbox.
3. Dependency chain resolution
Each package declares its own dependencies, which declare theirs. A single top-level package can pull in dozens of transitive dependencies. Attackers target these deep dependencies because they receive less scrutiny than popular packages.
4. Wheel vs. source distribution
Pre-compiled wheels execute faster but obscure their contents. Source distributions are transparent but require compilation, which executes build scripts. Either path creates risk: opaque binaries or arbitrary code execution during build.
5. Post-install scripts
Some packages register entry points or console scripts that modify your PATH or shell configuration. These persist after installation and execute whenever you start a new terminal session.
6. Import-time execution
Python executes module-level code when you first import a package. Even if you never call a function, the act of importing can trigger network requests, file operations, or credential harvesting.
7. Native extensions and C libraries
Packages with compiled extensions can bypass Python's runtime protections entirely. A malicious C extension has direct memory access and can persist outside your virtual environment.
8. Update and reinstallation
Pip's default behavior checks for updates. A package that was safe yesterday can become compromised today when its maintainer account is hijacked or a new version introduces malicious code.
Implications for Your TPRM Program
Your vendor assessment workflow probably includes SIG Core questionnaires for SaaS providers and security reviews for infrastructure vendors. However, the open-source dependencies your developers install daily receive no comparable scrutiny. Each package represents a third party with code execution rights in your environment.
The risk compounds because:
- You lack visibility into installation events. Most organizations don't log pip activity or correlate it with code commits.
- Developers bypass procurement. There's no intake process for PyPI packages, no criticality classification, no pre-contractual assessment.
- Dependency graphs are opaque. A package you trust might depend on packages you've never heard of, maintained by anonymous contributors.
- Substitutability is low. Once a package is embedded in your codebase, replacing it requires significant engineering effort.
This isn't hypothetical. The Python ecosystem has seen repeated supply chain attacks: typosquatting campaigns, dependency confusion exploits, and compromised maintainer accounts. The attack surface exists whether you acknowledge it or not.
Action Items by Priority
Immediate (this quarter):
Instrument your build pipelines. Log every pip install command with timestamp, package name, version, and user. Integrate these logs with your security information and event management system.
Pin all dependencies. Replace version ranges (
requests>=2.0) with exact pins (requests==2.31.0) in your requirements files. Generate a lockfile (pip freeze) for every environment.Enable hash verification. Use
pip install --require-hashesto verify that downloaded packages match expected cryptographic hashes. This prevents index compromise from delivering malicious code.
Near-term (next two quarters):
Deploy a private package index. Mirror approved packages internally using tools like Artifactory or a self-hosted PyPI server. Configure pip to pull only from your mirror, not directly from PyPI.
Implement pre-approval for new packages. Require developers to submit a request before adding dependencies. Review the package's maintainer history, GitHub activity, and existing security advisories.
Scan for known vulnerabilities. Integrate tools like Safety or pip-audit into your CI/CD pipeline to flag packages with published CVEs. Treat high-severity findings as build failures.
Strategic (six to twelve months):
Adopt software bill of materials (SBOM) generation. Produce machine-readable inventories of all dependencies for every application. Store these alongside your vendor inventory to enable concentration risk assessment across both commercial and open-source suppliers.
Establish a dependency review board. Create a cross-functional team (engineering, security, procurement) that evaluates high-risk packages, defines acceptable use policies, and maintains an approved package list.
Monitor for suspicious behavior post-installation. Deploy runtime application self-protection (RASP) or endpoint detection tools that flag unexpected network connections, file access, or process creation from Python interpreters.
Develop a vendor breach management plan for open source. Define notification timelines and incident escalation procedures for when a package you use is compromised. Know which applications are affected and how quickly you can patch or substitute.
Your organization's risk governance framework should extend to every trust boundary, including the one created when developers type pip install. The absence of a contract doesn't mean the absence of third-party risk.





