
Sicherheitshinweis: CVE-2026-38360 Pfad-Traversal (CWE-22) in dash-uploader (Python/PyPI)
Unauthentifizierte Path-Traversal-Schwachstelle in fohrloop/dash-uploader (Python, PyPI), die das Schreiben beliebiger Dateien ermöglicht und unter anderem zu Remote Code Execution (RCE), Überschreiben von Anwendungsquellcode, gespeichertem XSS und der Installation persistenter Backdoors führt.
Das Repository wurde am 2025-07-19 archiviert und hat keinen aktiven Maintainer. Jede veröffentlichte Version (0.1.0 bis 0.7.0a2) ist betroffen und wird es bleiben. Das Paket verzeichnet weiterhin etwa 28.000 monatliche Downloads.
Jeder, der dash-uploader in Produktion betreibt, muss selbst eine Gegenmaßnahme umsetzen. Die empfohlene Lösung ist die Migration auf die in Plotly Dash integrierte Komponente dcc.Upload. Alle Optionen finden Sie unter Mitigation.
| CVE-ID | CVE-2026-38360 (NVD) |
| Schwachstelle | Path Traversal (CWE-22) |
| CVSS 3.1 | 9.8 / Kritisch (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Produkt | dash-uploader |
| Betroffene Versionen | 0.1.0 bis 0.7.0a2 (alle 18 Releases) |
| Behobene Version | keine (Projekt am 2025-07-19 archiviert) |
| Angriffsvektor | Remote, ohne Authentifizierung |
| Entdecker | Muhammad Fitri Bin Mohd Sultan |
| Vergeben von | MITRE, 2026-05-07 |
| Verwandte CVEs | CVE-2026-38361 (DoS in derselben Bibliothek) |
Drei benutzerkontrollierte Parameter aus request.form.get() in dash_uploader/httprequesthandler.py werden ohne Bereinigung oder Validierung direkt an os.path.join() und os.makedirs() übergeben:
upload_id (Zeile 57 → Zeile 161, BaseHttpRequestHandler.get_temp_root): steuert das Zielverzeichnis. Ein Angreifer kann upload_id=../../../../usr/local/lib/python3.10/site-packages senden; die Dateien werden dann in das Paketverzeichnis von Python geschrieben.
resumableFilename (Zeile 51 → Zeile 108, BaseHttpRequestHandler._post): steuert den endgültigen Dateinamen. Ein Angreifer kann selbst mit einer legitimen upload_id über den Dateinamen aus dem Upload-Verzeichnis ausbrechen.
resumableIdentifier (Zeile 54 → Zeile 64, BaseHttpRequestHandler._post): wird zusammen mit os.makedirs() verwendet, um das temporäre Verzeichnis zu erstellen. Ein Angreifer kann an beliebiger Stelle im Dateisystem beliebige Verzeichnisse anlegen.
Der Upload-Endpunkt (standardmäßig /API/dash-uploader) erfordert keine Authentifizierung. Der in v0.5.0 hinzugefügte Hook http_request_handler ermöglicht Vorabprüfungen über post_before(), aber die verwundbare Methode _post() liest alle Parameter direkt aus request.form, nachdem der Hook zurückgekehrt ist. Der Hook kann Parameter nicht bereinigen, bevor die Bibliothek sie verarbeitet. Ein Entwickler, der über den Hook eine Authentifizierung hinzufügt, bleibt gegenüber Path Traversal durch einen authentifizierten Benutzer verwundbar.
# dash_uploader/httprequesthandler.py
def _post(self):
resumableFilename = request.form.get("resumableFilename", default="error", type=str)
resumableIdentifier = request.form.get("resumableIdentifier", default="error", type=str)
upload_id = request.form.get("upload_id", default="", type=str)
...
temp_root = self.get_temp_root(upload_id) # upload_id flows in here
temp_dir = os.path.join(temp_root, resumableIdentifier) # raw user input -> os.path.join
if not os.path.isdir(temp_dir):
os.makedirs(temp_dir) # raw user input -> os.makedirs
def get_temp_root(self, upload_id):
return os.path.join(self.upload_folder, upload_id) # no sanitization: ../../ escapes upload_folder
Drei unabhängige Traversal-Senken haben dieselbe Grundursache: Formularwerte erreichen os.path.join und os.makedirs ohne Validierung.
Ein nicht authentifizierter Remote-Angreifer sendet eine HTTP-POST-Multipart-Anfrage an den Upload-Endpunkt. Durch das Injizieren von Path-Traversal-Sequenzen (../) in den Formularparameter upload_id kontrolliert der Angreifer das Zielverzeichnis für die hochgeladene Datei. Beispielsweise schreibt upload_id=../../../../usr/local/lib/python3.10/site-packages Dateien in das Paketverzeichnis von Python und ermöglicht so beim nächsten Interpreterstart RCE durch die automatische Ausführung von .pth-Dateien.
Es sind keine Authentifizierung, kein Sitzungstoken und kein CSRF-Token erforderlich. Zwei weitere Parameter (resumableFilename und resumableIdentifier) bieten unabhängige Traversal-Vektoren über denselben Endpunkt. Die Standardkonfiguration der Bibliothek, wie sie in der offiziellen Quickstart-Dokumentation gezeigt wird, ist mit einem einzigen curl-Befehl ausnutzbar.
Beliebiges Schreiben von Dateien in jedes Verzeichnis, das für den Serverprozess beschreibbar ist. Dies führt über mehrere bekannte Primitive zu Remote Code Execution (RCE):
RCE-Primitive
.pth-Datei in site-packages. Führt beim nächsten Interpreterstart vom Angreifer bereitgestellten Code aus.sitecustomize.py oder usercustomize.py. Wird bei jedem Python-Start ausgeführt.app.wsgi, wsgi.py). Wird beim nächsten Worker-Reload ausgeführt./etc/cron.d/, /etc/cron.hourly/, User-Crontab-Spool), wenn der Prozess die erforderlichen Privilegien besitzt. Zeitgesteuerte Ausführung./etc/systemd/system/, ~/.config/systemd/user/). Wird beim nächsten Dienststart oder Neustart ausgeführt./etc/ld.so.preload, wenn der Prozess als Root läuft. Lädt Angreifercode in jede nachfolgende Ausführung von Binärdateien vor.~/.bashrc, ~/.profile, ~/.bash_profile). Wird beim nächsten interaktiven Login des Anwendungsbenutzers ausgeführt.~/.ssh/authorized_keys. Gewährt persistenten SSH-Zugriff auf den Host als Anwendungsbenutzer.Auswirkungen auf die Web-Ebene
site-packages), das jeden Benutzer bei jedem Seitenaufruf betrifft, bis die Anwendung neu gestartet wirdAuswirkungen auf das Dateisystem
os.makedirs() mit dem nicht bereinigten Parameter resumableIdentifier (nutzbar zur Inode-Erschöpfung oder zum Vorbereiten von Schreibvorgängen in nicht vorhandene Verzeichnisbäume)dash_uploader/httprequesthandler.pyBaseHttpRequestHandler.get_temp_root()BaseHttpRequestHandler._post()Optionen für Benutzer, die die Bibliothek derzeit im Einsatz haben, in der Reihenfolge der Präferenz:
Migrieren Sie zu dcc.Upload, der offiziellen Upload-Komponente, die mit Plotly Dash ausgeliefert wird. Dateien treffen im Callback als base64-String ein; es wird kein Handler offengelegt, der in das Dateisystem schreibt, und es existiert kein clientkontrollierter Zielpfad, daher ist diese Fehlerklasse hier nicht anwendbar. Am besten geeignet für kleine und mittlere Dateien. Für sehr große Uploads siehe Punkt 2.
Schreiben Sie einen schlanken Flask-Upload-Handler mit werkzeug.utils.secure_filename() und einem fest codierten serverseitigen Zielverzeichnis. Akzeptieren Sie niemals vom Client gelieferte Werte für upload_id, Dateinamen oder Identifier als Pfadkomponenten.
Falls Sie dash-uploader weiterhin verwenden, platzieren Sie den Upload-Endpunkt hinter einer Authentifizierung UND validieren Sie upload_id, resumableFilename und resumableIdentifier anhand einer strengen Allowlist (z. B. nur UUIDs) auf einer Ebene, die die Anfrage umschreibt oder ablehnt, bevor der Handler der Bibliothek sie sieht. Der Hook http_request_handler der Bibliothek verhindert das Traversal NICHT, da die Parameter aus request.form gelesen werden, nachdem der Hook zurückgekehrt ist; die Bereinigung muss oberhalb der Bibliothek erfolgen.
Auf der Reverse-Proxy- oder WAF-Ebene lehnen Sie jede Anfrage an den Upload-Endpunkt ab, bei der ein Formularfeld .., codierte Varianten (%2e%2e, ..%2f, %2e%2e%2f) oder absolute Pfade enthält.
| Datum | Ereignis |
|---|---|
| 2026-03-17 | Schwachstelle während der Sicherheitsforschung auf einer Produktionsinstallation entdeckt. |
| 2026-03-19 | CVE-Anfrage bei MITRE eingereicht. |
| 2026-05-07 | CVE-2026-38360 von MITRE vergeben. |
| 2026-05-07 | Öffentliche Sicherheitswarnung veröffentlicht. |
| 2026-05-09 | CVE-Eintrag in der MITRE-CVE-Datenbank und der NVD veröffentlicht. |
0.6.1 (stabile Linie). Vorabversionen reichen bis 0.7.0a2.dash. Optionale Abhängigkeit: pyyaml. Lizenz: MIT.Muhammad Fitri Bin Mohd Sultan