
Installing a Python package usually looks simple: run pip install, wait for dependency resolution, and start using the library. However, package installation isn't always passive. Python packaging tools may need to inspect package metadata, execute build backends, create wheels, and run installation-related code.
This becomes a security concern when the package being installed is untrusted or has been modified unexpectedly. A malicious package may attempt to execute Python code during installation, before the application itself ever imports the package.
pip 26.3 introduces an important security change for this situation. It blocks unexpected imports during installation, warns about unsafe imports afterward, and improves recovery from interrupted installations. The change aims to reduce the amount of third-party Python code that can unexpectedly execute during installation.
This does not mean pip can make every Python package safe. pip's own security documentation makes clear that installing untrusted wheels has never been considered completely safe because Python's import system is dynamic.
Why Import Execution During Installation Is a Security Problem
Python packages can contain much more than ordinary application modules. A distribution can include:
A traditional installation workflow can therefore involve several stages where Python code may be loaded.
For example, consider a project with a package structure like this:
myapp/
├── pyproject.toml
├── src/
│ └── myapp/
│ ├── __init__.py
│ └── cli.py
└── README.md
The __init__.py file may contain executable Python code:
print("Package imported")
Normally, importing the package is expected to execute that code.
The security problem occurs when an installation process imports code that was not expected to be imported at that point.
If the package is compromised, that code could perform actions such as reading environment variables, accessing files, making network requests, or modifying the local environment.
The important distinction is that this risk exists before your application intentionally imports the package.
What Changed in pip 26.3
pip 26.3 includes a change specifically described as:
Block unexpected imports during installation,
warn about unsafe imports afterward,
and improve recovery from interrupted installations.
This change is part of pip's 26.3 release and is associated with issue #13842.
The practical goal is to make installation behavior more predictable.
Instead of assuming that every import encountered during installation is acceptable, pip can distinguish expected installation activity from unexpected imports and take action when unsafe behavior is detected.
This is especially useful in automated environments where dependencies are installed during:
Understanding Expected and Unexpected Imports
Not every import during installation is automatically malicious.
Python packaging itself relies on imports in several legitimate situations. Build systems can require Python modules to prepare metadata or build distributions.
For example, a project may define a build backend in pyproject.toml:
[build-system]
requires = ["setuptools>=80"]
build-backend = "setuptools.build_meta"
The build process needs to load the configured backend.
That is different from an unrelated package unexpectedly importing application code or another module simply because it happens to be present in the environment.
The important security principle is therefore not:
Block every import.
It is closer to:
Allow installation-related imports that pip expects,
while detecting unexpected imports that could indicate unsafe behavior.
This distinction matters when troubleshooting a package installation failure after upgrading pip.
Check Your pip Version
Before testing the new behavior, verify the pip version being used by the environment.
python -m pip --version
A typical result looks similar to:
pip 26.3 from .../site-packages/pip (python 3.12)
Using:
python -m pip
is preferable to relying on a globally available pip command because it makes it clearer which Python interpreter is executing pip.
You can also check:
python -m pip show pip
If your project uses multiple Python installations, verify the interpreter and pip together:
python --version
python -m pip --version
This avoids a common troubleshooting mistake where pip belongs to a different Python environment than the application.
Test Package Installation in an Isolated Environment
Do not test potentially unsafe packages directly inside a production environment.
Create a virtual environment first:
python -m venv .venv
Activate it on Windows:
.venv\Scripts\Activate.ps1
On Linux or macOS:
source .venv/bin/activate
Then verify the environment:
python --version
python -m pip --version
This provides a controlled location for testing package installation behavior.
For security testing, an isolated environment is still not equivalent to a sandbox. A virtual environment limits Python package changes, but it does not provide a complete security boundary against malicious native code or operating-system-level activity.
Use Installation Logs When Investigating Import Warnings
If pip reports an unexpected or unsafe import during installation, do not immediately bypass the warning.
First capture the installation output.
For example:
python -m pip install example-package -v
For deeper diagnostics:
python -m pip install example-package -vv
Verbose output can help identify which package, build step, or backend was involved.
You can also generate a log file:
python -m pip install example-package --log pip-install.log
The useful troubleshooting question is:
Which package caused the import, and why was that import required?
That is more useful than simply asking whether the installation succeeded.
Check the Package Before Installing It
pip's import protection should be treated as one layer of security rather than the complete solution.
Before installing a package in a production environment, check where it comes from.
For example:
python -m pip index versions example-package
For internal packages, verify that the configured package index is the expected one.
You should also review the package version specified by your project:
example-package==2.4.1
Pinning versions makes dependency changes easier to review.
For higher-risk applications, use hashes where appropriate:
example-package==2.4.1 \
--hash=sha256:<expected-hash>
Hash checking helps ensure that the downloaded artifact matches the artifact your dependency configuration expects. It does not prove that the package itself is trustworthy.
Test Installation in CI
CI pipelines are one of the places where unexpected installation behavior deserves particular attention.
A simple installation step might look like:
steps:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
After moving to pip 26.3, monitor the installation logs for import-related warnings or failures.
For security-sensitive projects, avoid silently ignoring installation warnings.
A better pipeline pattern is:
Resolve dependencies
↓
Verify dependency versions
↓
Install in isolated environment
↓
Review installation warnings
↓
Run tests
↓
Build deployment artifact
This makes dependency installation part of the software supply-chain process rather than treating it as an invisible setup step.
Common Mistakes
Assuming every pip warning means the package is malicious
An installation warning is a signal that deserves investigation. It is not automatically proof of malicious behavior.
First identify the package and installation stage involved.
Installing untrusted packages on the host system
Avoid testing unknown packages in an environment containing production credentials, SSH keys, cloud credentials, or sensitive source code.
Use a disposable environment with minimal permissions.
Assuming a virtual environment is a security sandbox
A virtual environment separates Python dependencies, but it does not isolate operating-system capabilities.
Do not treat:
python -m venv test-env
as equivalent to a container or hardened sandbox.
Ignoring package build dependencies
A package can execute code through its build process as well as through its normal runtime modules.
Review pyproject.toml and the declared build backend when investigating unusual installation behavior.
Downgrading pip immediately
If an existing installation starts failing after a pip upgrade, first determine whether the failure is related to the new security behavior.
Blindly downgrading can remove security improvements without addressing the underlying package problem.
Best Practices for Production Projects
Practice | Why it matters |
|---|
Use isolated environments | Limits dependency changes |
Pin important dependencies | Makes dependency changes predictable |
Review package sources | Reduces supply-chain risk |
Monitor pip installation logs | Helps detect unexpected behavior |
Keep pip updated | Receives security and compatibility fixes |
Use dependency hashes where appropriate | Verifies downloaded artifacts |
Minimize CI credentials | Limits impact if a package is compromised |
Test dependency updates separately | Prevents unexpected changes from reaching production |
The most important point is that pip's new protection should complement, not replace, dependency security practices.
Troubleshooting Checklist
If a package installation behaves differently after upgrading to pip 26.3, work through the following checks:
Confirm the pip version.
python -m pip --version
Reproduce the issue inside a clean virtual environment.
python -m venv test-env
Install the package with verbose logging.
python -m pip install package-name -vv
Identify the package or build backend associated with the import warning.
Check whether the package is coming from the expected package index.
Review the project's pyproject.toml and build-system configuration.
Check whether the package has a newer release that resolves the installation problem.
Only consider a pip downgrade after understanding the compatibility or security trade-off.
Advantages and Disadvantages
Advantages
Reduces unexpected imports during package installation.
Makes unsafe installation behavior easier to identify.
Improves recovery from interrupted installations.
Adds another layer of protection to Python dependency installation.
Particularly useful for CI/CD and automated build environments.
Disadvantages
Some existing packages or unusual build workflows may expose compatibility issues.
Troubleshooting can require understanding Python packaging and build backends.
The feature does not make untrusted Python packages completely safe.
Virtual environments alone are still insufficient for executing highly untrusted code.
Summary
pip 26.3 makes package installation safer by blocking unexpected imports, warning about unsafe imports afterward, and improving recovery from interrupted installations. This is an important change for developers who install dependencies automatically through CI/CD, Docker builds, and deployment pipelines.
The right approach is not to treat the new behavior as a replacement for dependency security. Use isolated environments, review package sources, pin dependencies where appropriate, monitor installation logs, and investigate unexpected imports instead of immediately bypassing them.
For production Python projects, dependency installation should be treated as part of the software supply chain. The safer the installation process, the fewer opportunities there are for unexpected package behavior to reach your development or production environments.
Join the conversation! Your thoughts help the community grow.