
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 OS Command InjectionGravità: 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 (OS Command Injection), CWE-20 (Improper Input Validation)
Scoperto e segnalato da: Sai Teja Erukude
Le versioni di Frictionless fino alla prerelease 5.20.0rc1 inclusa contengono una
vulnerabilità di OS command injection nel comando CLI frictionless explore.
Il comando carica un descrittore 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 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 Data Package in cui resources[0].path contiene un
payload innocuo che scrive un file marcatore.
Su Windows, il percorso generato utilizza & come separatore di comandi:
data.csv & echo frictionless_explore_command_injection_triggered>"...\marker.txt" & rem
Sui sistemi POSIX, il percorso generato utilizza il punto e virgola come separatore di comandi:
data.csv; printf %s frictionless_explore_command_injection_triggered > .../marker.txt; #
Il runner invoca il vero comando frictionless explore dal pacchetto installato.
Azzera PATH per il processo figlio in modo che il visualizzatore vd previsto non
si avvii 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 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.
Inserire in blacklist caratteri specifici dei percorsi è una soluzione più debole perché la sintassi della shell varia tra piattaforme e shell. Il confine dell'invocazione del comando è la causa principale, quindi la correzione duratura dovrebbe evitare l'interpretazione da parte della shell.
Vedere fix.md per una patch suggerita.
Scoperto e segnalato da Sai Teja Erukude.
La divulgazione è stata coordinata tramite VulnCheck.
exploit_walkthrough.mdfix.md