CVE-2026-113717: virtualenv · Pip seeding with download omits wheel digest verification
Affects noxSource GCVE Database
Not known to be exploited · CVSS 2.3 Low : upgrade to 2026.10.20 when convenient.
Data as of 27 Oct 2026, 06:43 UTC
- Patch
- Available – fixed in 2026.10.20
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:L/VA:L/SC:N/SI:N/SA:NExploitation evidence
Disclosed: evidence found.
CVE published 20 Oct 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponised: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 26 Oct 2026.
What to do
Upgrade nox to 2026.10.20.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
Homebrewnoxpkg:brew/noxOther threats | Affected
| Fixed in
|
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
Description
## Summary The pip seeder acquires bundled wheels with download=False and lets pip access the index when --download is selected. Index candidates on that path do not pass through virtualenv's wheel digest verification. Anthropic's OSS Scanner reported this as `ANT-2026-74ALJBUF` in `virtualenv-20261015-005`, received on 15 October 2026. ## Affected area Wheel selection by the pip seeder when downloads are enabled. ## Attacker-controlled input The pip seeder and download option must be selected. The finding concerns the default-index digest-verification policy. Explicit custom-index settings already opt out of comparison against PyPI metadata; this patch retains that policy. ## Affected code The relevant 21.14.8 source is in [pip seeder](https://github.com/pypa/virtualenv/blob/a795ab116356afde11039cf2763d77e8a06da738/src/virtualenv/seed/embed/pip_invoke.py). ## Mechanism With `--seeder pip --download`, `PipInvoke.get_pip_install_cmd()` first calls `get_wheel(download=False)`, so virtualenv's `download_wheel()` and `verify_wheel_digest()` are skipped. It then lets `pip install` consult the configured index. An index wheel with the same package and version as the bundled wheel can be selected without virtualenv comparing its SHA-256 with PyPI metadata. The default app-data seeder takes the verification path for the same option. ## Reproduction and evidence The scanner built a local index named in `pip.conf` that served a modified copy of the bundled pip wheel under the same filename. In the control run, `virtualenv --download env-default` rejected the wheel with a digest mismatch. In the second run, adding `--seeder pip` produced an environment whose installed `pip/__init__.py` matched the index wheel; `env-pip/bin/pip --version` ran the added line. The reproducer checked the installed bytes and marker before reporting `BUG`. Both `--seeder pip` and `--download` are needed. The report used a non-PyPI index from `pip.conf` and left `PIP_INDEX_URL`, `PIP_EXTRA_INDEX_URL`, and `PIP_INDEX` unset, so virtualenv's default-seeder PyPI comparison remained active. This does not establish index control in the default PyPI setup. The unchecked pip-seeder download path is older, while the comparison with the default seeder arose when digest verification was added in 21.7.12. [PR #3430](https://github.com/pypa/virtualenv/pull/3430) acquires and verifies selected wheels before invoking pip with index lookup disabled. ## Attack sequence ```mermaid sequenceDiagram participant I as Index in pip.conf participant V as virtualenv PipInvoke participant P as pip install participant E as Seeded environment I->>V: serve modified pip wheel V->>V: get_wheel(download=False) V->>P: install with --download permitting index lookup P->>I: select same-version index wheel I->>E: modified pip installed without virtualenv digest check E->>E: later pip invocation runs added code Note over V,E: Default app-data seeder rejects the same digest ``` ## Reproducer files The following files are from the scanner report for `ANT-2026-74ALJBUF`. They were tested against commit `a857a7823c73` in the scanner image. The `repro` entrypoint expects companion files under `/tmp/repro.d`; cases that change user IDs need a disposable root-capable container. The last output line is `BUG` when the reported behavior occurs. These files are included as evidence and were not rerun for this advisory update. **`repro`** ```text #!/usr/bin/env python3 import glob import hashlib import json import os import shutil import subprocess import sys import zipfile from virtualenv.seed.wheels.embed import get_embed_wheel companions = "/tmp/repro.d" work = "/tmp/repro-pip-seeder-download" shutil.rmtree(work, ignore_errors=True) os.makedirs(work) # set up: the pip wheel virtualenv bundles, and PyPI's record of its sha256 (served by virtualenv_offline.py: no network) bundled = get_embed_wheel("pip", f"{sys.version_info.major}.{sys.version_info.minor}") pypi_sha256 = hashlib.sha256(open(bundled.path, "rb").read()).hexdigest() pypi_release = {"filename": bundled.name, "digests": {"sha256": pypi_sha256}} os.makedirs(f"{work}/pypi.org/pypi/pip") with open(f"{work}/pypi.org/pypi/pip/json", "w") as pypi_json: json.dump({"releases": {bundled.version: [pypi_release]}}, pypi_json) # attacker: the mirror serves other bytes under the bundled wheel's own file name marker = f"{work}/MIRROR_CODE_RAN" subprocess.run([sys.executable, f"{companions}/make_mirror.py", str(bundled.path), f"{work}/mirror", marker], check=True) mirror_wheel = f"{work}/mirror/pip/{bundled.name}" mirror_sha256 = hashlib.sha256(open(mirror_wheel, "rb").read()).hexdigest() print(f"{bundled.name}: PyPI publishes sha256 {pypi_sha256}") print(f"{bundled.name}: the mirror serves sha256 {mirror_sha256}") # user: pip.conf names the mirror; PIP_INDEX_URL, PIP_EXTRA_INDEX_URL and PIP_INDEX (which turn the check off) are unset with open(f"{work}/pip.conf", "w") a
References
- github.com/pypa/virtualenv/security/advisories/GHSA-cx28-75q4-x26q (opens in a new tab)
- nvd.nist.gov/vuln/detail/CVE-2026-113717 (opens in a new tab)
- github.com/pypa/virtualenv/pull/3430 (opens in a new tab)
- github.com/pypa/virtualenv/commit/7babec66e043e1cc8bc66869a063653898719d96 (opens in a new tab)
- github.com/pypa/virtualenv (opens in a new tab)
- github.com/pypa/virtualenv/releases/tag/21.14.9 (opens in a new tab)