
Proof-of-Concept für CVE-2026-93349, eine OS-Befehlsinjektion in Frictionless <= 5.20.0rc1 explore CLI über bösartige Data-Package-Descriptor-Pfade.
<= 5.20.0rc1 explore OS Command InjectionSchweregrad: Hoch, CVSS 3.1 8.8
Vektor: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Betroffen: alle Frictionless-Versionen <= 5.20.0rc1
Komponente: frictionless.console.commands.explore
CWE: CWE-78 (OS Command Injection), CWE-20 (Improper Input Validation)
Gemeldet von: Sai Teja Erukude
Frictionless-Versionen bis einschließlich der Vorabversion 5.20.0rc1 enthalten
eine OS Command Injection-Schwachstelle im CLI-Befehl frictionless explore.
Der Befehl lädt einen vom Benutzer bereitgestellten Data Package-Deskriptor,
sammelt Ressourcenpfade, leitet resource.normpath ab, fügt diese Pfade zu einer
einzigen Befehlszeichenkette zusammen und übergibt diese Zeichenkette direkt an
os.system:
paths = [resource.normpath for resource in resources if resource.normpath]
os.system(f"vd {' '.join(paths)}")
Da resources[*].path deskriptorgesteuerte Metadaten aus datapackage.json
sind, kann ein Angreifer Shell-Metazeichen in einen Ressourcenpfad einfügen.
Wenn ein Opfer frictionless explore auf dem bösartigen Deskriptor ausführt,
interpretiert die Shell diese Metazeichen und führt den eingeschleusten Befehl
aus.
Ein Angreifer kann beliebige Befehle im Sicherheitskontext des Benutzers
ausführen, der frictionless explore ausführt.
Dies kann Workflows beeinträchtigen, in denen Benutzer Data Package-Deskriptoren aus nicht vertrauenswürdigen Projekten, Archiven, Repositories oder gemeinsam genutzten Datensätzen inspizieren, validieren oder erkunden.
Je nach lokaler Umgebung kann dies Folgendes ermöglichen:
Der anfällige Pfad ist der Befehl explore:
frictionless explore <package>
-> Package.from_descriptor(...)
-> Resource.list()
-> resource.normpath
-> os.system(f"vd {' '.join(paths)}")
Der PoC generiert einen Data Package-Deskriptor, bei dem resources[0].path
eine harmlose Marker-Datei-Schreibnutzlast enthält.
Unter Windows verwendet der generierte Pfad &-Befehlstrenner:
data.csv & echo frictionless_explore_command_injection_triggered>"...\marker.txt" & rem
Auf POSIX-Systemen verwendet der generierte Pfad Semikolon-Befehlstrenner:
data.csv; printf %s frictionless_explore_command_injection_triggered > .../marker.txt; #
Der Runner ruft den echten Befehl frictionless explore aus dem installierten
Paket auf. Er leert PATH für den Kindprozess, damit der vorgesehene
vd-Viewer nicht interaktiv gestartet wird, aber der eingeschleuste Befehl
wird dennoch ausgeführt, wenn die Shell die konstruierte Befehlszeichenkette
parst.
package_builder.py erstellt den angreifergesteuerten
Data Package-Deskriptor und eine harmlose CSV-Datei.
run_poc.py validiert den Deskriptor, ruft
frictionless explore auf und gibt Ausführungsnachweise aus.
Nur in einer lokalen Testumgebung ausführen:
python -m venv .venv
.venv\Scripts\activate
python -m pip install -r requirements.txt
python -B run_poc.py
Die enthaltene requirements.txt pinnt frictionless==5.20.0rc1, die neueste
bestätigte anfällige Vorabversion in diesem Bereich.
Erwarteter Nachweis bei anfälligen Versionen:
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
Der wichtige Nachweis ist, dass der bösartige Deskriptor gültig ist, der
deskriptorgesteuerte Pfad bis in resource.normpath überlebt und marker.txt
nach der Ausführung von frictionless explore erstellt wird.
Die Nutzlast ist absichtlich harmlos. Sie schreibt nur diese lokale Marker-Zeichenkette:
frictionless_explore_command_injection_triggered
Sie startet keine Shell-Sitzung, verbindet sich mit keinem Netzwerkdienst, liest keine Geheimnisse, löscht keine Daten und ändert keine Dateien außerhalb des PoC-Verzeichnisses.
Vermeiden Sie es, deskriptorgesteuerte Pfade an eine Shell zu übergeben.
Ersetzen Sie den shell-basierten Aufruf durch subprocess.run mit einem
Argumentvektor:
subprocess.run(["vd", *paths], check=False)
Dies übergibt jeden Ressourcenpfad als wörtliches Argument an vd.
Shell-Metazeichen innerhalb eines Pfades bleiben gewöhnliche Zeichen innerhalb
dieses einzelnen argv-Eintrags und werden nicht ausgeführt.
Das Blacklisting bestimmter Pfadzeichen ist schwächer, da die Shell-Syntax je nach Plattform und Shell variiert. Die Befehlsaufrufgrenze ist die Grundursache, daher sollte die dauerhafte Lösung die Shell-Interpretation vermeiden.
Siehe fix.md für einen vorgeschlagenen Patch.
Entdeckt und gemeldet von Sai Teja Erukude, koordiniert über VulnCheck.
exploit_walkthrough.mdfix.md