
Avviso: CVE-2026-38360 attraversamento di percorso (CWE-22) in dash-uploader (Python/PyPI)
Path traversal non autenticato in fohrloop/dash-uploader (Python, PyPI) che consente la scrittura arbitraria di file, portando, ma non solo, a Remote Code Execution (RCE), sovrascrittura del codice sorgente dell'applicazione, XSS persistente e installazione di backdoor persistenti.
Il repository è stato archiviato il 19 luglio 2025 senza un maintainer attivo. Ogni versione pubblicata (da 0.1.0 a 0.7.0a2) è vulnerabile e lo resterà. Il pacchetto registra ancora circa 28.000 download mensili.
Chiunque esegua dash-uploader in produzione deve applicare una mitigazione autonomamente. La soluzione consigliata è migrare al componente dcc.Upload integrato in Plotly Dash. Vedi Mitigazione per tutte le opzioni.
| ID CVE | CVE-2026-38360 (NVD) |
| Vulnerabilità | Path Traversal (CWE-22) |
| CVSS 3.1 | 9.8 / Critico (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Prodotto | dash-uploader |
| Versioni interessate | da 0.1.0 a 0.7.0a2 (tutte le 18 release) |
| Versione corretta | nessuna (progetto archiviato il 19 luglio 2025) |
| Vettore d'attacco | Remoto, non autenticato |
| Scopritore | Muhammad Fitri Bin Mohd Sultan |
| Assegnato da | MITRE, 2026-05-07 |
| Correlato | CVE-2026-38361 (DoS nella stessa libreria) |
Tre parametri controllabili dall'utente prelevati da request.form.get() in dash_uploader/httprequesthandler.py vengono passati direttamente a os.path.join() e os.makedirs() senza alcuna sanitizzazione o validazione:
upload_id (riga 57 → riga 161, BaseHttpRequestHandler.get_temp_root): controlla la directory di destinazione. Un attaccante può inviare upload_id=../../../../usr/local/lib/python3.10/site-packages e i file vengono scritti nella directory dei pacchetti di Python.
resumableFilename (riga 51 → riga 108, BaseHttpRequestHandler._post): controlla il nome file finale. Un attaccante può uscire dalla directory di upload tramite il nome file anche con un upload_id legittimo.
resumableIdentifier (riga 54 → riga 64, BaseHttpRequestHandler._post): usato con os.makedirs() per creare la directory temporanea. Un attaccante può creare directory arbitrarie in qualsiasi punto del filesystem.
L'endpoint di upload (/API/dash-uploader di default) non richiede autenticazione. L'hook http_request_handler, aggiunto nella v0.5.0, consente controlli pre-richiesta tramite post_before(), ma il metodo vulnerabile _post() legge tutti i parametri direttamente da request.form dopo che l'hook è terminato. L'hook non può sanificare i parametri prima che la libreria li elabori. Uno sviluppatore che aggiunge l'autenticazione tramite l'hook resta comunque vulnerabile al path traversal da parte di un utente autenticato.
# 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
Tre sink di traversal indipendenti condividono la stessa causa principale: i valori del form raggiungono os.path.join e os.makedirs senza alcuna validazione.
Un attaccante remoto non autenticato invia una richiesta HTTP POST multipart all'endpoint di upload. Iniettando sequenze di path traversal (../) nel parametro del form upload_id, l'attaccante controlla la directory di destinazione del file caricato. Ad esempio, upload_id=../../../../usr/local/lib/python3.10/site-packages scrive i file nella directory dei pacchetti di Python, consentendo RCE al successivo avvio dell'interprete tramite l'esecuzione automatica di .pth.
Non è richiesta alcuna autenticazione, né token di sessione, né token CSRF. Due parametri aggiuntivi (resumableFilename e resumableIdentifier) forniscono vettori di traversal indipendenti attraverso lo stesso endpoint. La configurazione predefinita della libreria, come mostrato nella documentazione ufficiale quickstart, è sfruttabile con un singolo comando curl.
Scrittura arbitraria di file in qualsiasi directory scrivibile dal processo del server. Ciò si traduce in Remote Code Execution (RCE) attraverso diverse primitive note.
Primitive RCE
.pth inserito in site-packages. Esegue il codice fornito dall'attaccante al successivo avvio dell'interprete.sitecustomize.py o usercustomize.py. Esegue a ogni avvio di Python.app.wsgi, wsgi.py). Esegue al successivo reload del worker./etc/cron.d/, /etc/cron.hourly/, spool crontab utente) quando il processo dispone dei privilegi necessari. Esecuzione programmata./etc/systemd/system/, ~/.config/systemd/user/). Esegue al successivo avvio del servizio o al riavvio./etc/ld.so.preload quando il processo viene eseguito come root. Precarica il codice dell'attaccante in ogni successiva esecuzione di binari.~/.bashrc, ~/.profile, ~/.bash_profile). Esegue al prossimo login interattivo dell'utente dell'applicazione.~/.ssh/authorized_keys. Concede accesso SSH persistente all'host come utente dell'applicazione.Impatto a livello web