
إعلان: CVE-2026-38360 اجتياز المسار (CWE-22) في dash-uploader (Python/PyPI)
ثغرة اجتياز مسار غير مصادق عليها في fohrloop/dash-uploader (Python، PyPI) تتيح الكتابة العشوائية للملفات، مما يؤدي إلى (على سبيل المثال لا الحصر) تنفيذ التعليمات البرمجية عن بُعد (RCE)، واستبدال الكود المصدري للتطبيق، وXSS مخزّنة، وتثبيت باب خلفي دائم.
تمت أرشفة المستودع في 2025-07-19 دون وجود مُطوِّر نشط. جميع الإصدارات المنشورة (من 0.1.0 إلى 0.7.0a2) متأثرة وستبقى كذلك. لا تزال الحزمة تحقق حوالي 28,000 تنزيل شهريًا.
يجب على أي شخص يشغّل dash-uploader في بيئة إنتاج تطبيق إجراءً علاجيًا بنفسه. الإصلاح الموصى به هو الانتقال إلى مكوّن dcc.Upload المدمج في Plotly Dash. راجع إجراءات التخفيف للاطلاع على الخيارات الكاملة.
| معرّف CVE | CVE-2026-38360 (NVD) |
| نوع الثغرة | اجتياز المسار (CWE-22) |
| CVSS 3.1 | 9.8 / حرجة (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| المنتج | dash-uploader |
| الإصدارات المتأثرة | من 0.1.0 إلى 0.7.0a2 (جميع الإصدارات الـ18) |
| الإصدار المُصحَّح | لا يوجد (تمت أرشفة المشروع في 2025-07-19) |
| متجه الهجوم | عن بُعد، بدون مصادقة |
| المكتشف | Muhammad Fitri Bin Mohd Sultan |
| مُعيّن بواسطة | MITRE، 2026-05-07 |
| ذات صلة | CVE-2026-38361 (ثغرة حجب الخدمة DoS في المكتبة نفسها) |
يتم تمرير ثلاث معاملات يتحكم فيها المستخدم من request.form.get() في dash_uploader/httprequesthandler.py مباشرةً إلى os.path.join() و os.makedirs() دون أي تنقية أو تحقق:
upload_id (السطر 57 → السطر 161، BaseHttpRequestHandler.get_temp_root): يتحكم في دليل الوجهة. يمكن للمهاجم إرسال upload_id=../../../../usr/local/lib/python3.10/site-packages فتُكتب الملفات في دليل حزم Python.
resumableFilename (السطر 51 → السطر 108، BaseHttpRequestHandler._post): يتحكم في اسم الملف النهائي. يمكن للمهاجم الخروج من دليل الرفع عبر اسم الملف حتى مع upload_id شرعي.
resumableIdentifier (السطر 54 → السطر 64، BaseHttpRequestHandler._post): يُستخدم مع os.makedirs() لإنشاء الدليل المؤقت. يمكن للمهاجم إنشاء أدلة عشوائية في أي مكان على نظام الملفات.
لا تتطلب نقطة نهاية الرفع (/API/dash-uploader افتراضيًا) أي مصادقة. يتيح خطاف http_request_handler المُضاف في v0.5.0 إجراء فحوصات ما قبل الطلب عبر post_before()، لكن طريقة _post() المعيبة تقرأ جميع المعاملات مباشرةً من request.form بعد عودة الخطاف. لا يمكن للخطاف تنقية المعاملات قبل معالجتها بواسطة المكتبة. المطوّر الذي يضيف مصادقة عبر الخطاف يظل عرضة لاجتياز المسار من مستخدم مصادَق.
# dash_uploader/httprequesthandler.py
def _post(self):
resumableFilename = request.form.get("resumableFilename", default="error", type=str)
resumableIdentifier = request.form.get("resumableIdentifier", default="error", type=str)
upload_id = request.form.get("upload_id", default="", type=str)
...
temp_root = self.get_temp_root(upload_id) # upload_id flows in here
temp_dir = os.path.join(temp_root, resumableIdentifier) # raw user input -> os.path.join
if not os.path.isdir(temp_dir):
os.makedirs(temp_dir) # raw user input -> os.makedirs
def get_temp_root(self, upload_id):
return os.path.join(self.upload_folder, upload_id) # no sanitization: ../../ escapes upload_folder
تتشارك ثلاث نقاط اجتياز مستقلة في السبب الجذري نفسه: تصل قيم النموذج إلى os.path.join و os.makedirs دون أي تحقق.
يرسل مهاجم عن بُعد غير مصادَق طلب HTTP POST متعدد الأجزاء (multipart) إلى نقطة نهاية الرفع. عن طريق حقن تسلسلات اجتياز المسار (../) في معامل النموذج upload_id، يتحكم المهاجم في دليل الوجهة للملف المرفوع. على سبيل المثال، يؤدي upload_id=../../../../usr/local/lib/python3.10/site-packages إلى كتابة ملفات في دليل حزم Python، مما يتيح تنفيذ التعليمات البرمجية عن بُعد (RCE) عند بدء التشغيل التالي للمفسّر عبر التنفيذ التلقائي لملفات .pth.
لا يلزم أي مصادقة أو رمز جلسة أو رمز CSRF. يوفر معاملان إضافيان (resumableFilename و resumableIdentifier) متجهَي اجتياز مستقلين عبر نقطة النهاية نفسها. التكوين الافتراضي للمكتبة كما هو موضح في وثائق البدء السريع الرسمية قابل للاستغلال بأمر curl واحد.
كتابة ملفات عشوائية إلى أي دليل قابل للكتابة بواسطة عملية الخادم. يترجم هذا إلى تنفيذ التعليمات البرمجية عن بُعد (RCE) عبر عدة آليات معروفة:
آليات RCE
.pth بلغة Python في site-packages. ينفّذ كودًا يوفره المهاجم عند بدء التشغيل التالي للمفسّر.sitecustomize.py أو usercustomize.py. يُنفَّذ عند كل بدء تشغيل لـ Python.app.wsgi و wsgi.py). يُنفَّذ عند إعادة تحميل العامل التالية./etc/cron.d/، /etc/cron.hourly/، رصة crontab الخاصة بالمستخدم) عندما تتمتع العملية بالصلاحيات اللازمة. تنفيذ مجدول./etc/systemd/system/، ~/.config/systemd/user/). يُنفَّذ عند بدء الخدمة التالي أو إعادة التشغيل./etc/ld.so.preload عندما تعمل العملية بصلاحيات الجذر (root). يحمّل كود المهاجم مسبقًا في كل تنفيذ ثنائي لاحق.~/.bashrc، ~/.profile، ~/.bash_profile). يُنفَّذ عند تسجيل الدخول التفاعلي التالي لمستخدم التطبيق.~/.ssh/authorized_keys. يمنح وصول SSH دائمًا إلى المضيف بصلاحيات مستخدم التطبيق.الأثر على مستوى الويب
site-packages)، مما يؤثر على كل مستخدم عند كل تحميل صفحة حتى تتم إعادة تشغيل التطبيق.الأثر على نظام الملفات
os.makedirs() مع معامل resumableIdentifier غير المنقّى (قابل للاستخدام لاستنزاف inode أو لتهيئة كتابات في أشجار أدلة غير موجودة).dash_uploader/httprequesthandler.pyBaseHttpRequestHandler.get_temp_root()BaseHttpRequestHandler._post()الخيارات المتاحة للمستخدمين الذين لديهم نسخ منصوبة حاليًا، مرتبة حسب الأفضلية:
dcc.Upload، مكوّن الرفع الرسمي المرفق مع Plotly Dash. تصل الملفات إلى دالة الاستدعاء (callback) كسلسلة base64؛ لا يوجد معالج للكتابة على نظام الملفات مكشوف ولا يوجد مسار وجهة يتحكم فيه العميل، لذلك لا تنطبق فئة الثغرة هذه. الأنسب للملفات الصغيرة والمتوسطة. بالنسبة للملفات الكبيرة جدًا، انظر البند 2.werkzeug.utils.secure_filename() ودليل وجهة ثابت في الخادم. لا تقبل أبدًا قيم upload_id أو اسم الملف أو المعرّف المقدمة من العميل كمكوّنات للمسار.upload_id و resumableFilename و resumableIdentifier مقابل قائمة مسموح بها صارمة (مثل UUID فقط) في طبقة تعيد كتابة الطلب أو ترفضه قبل أن يراه معالج المكتبة. خطاف http_request_handler الخاص بالمكتبة لا يمنع الاجتياز لأن المعاملات تُقرأ من request.form بعد عودة الخطاف؛ يجب أن تتم التنقية فوق المكتبة... أو صيغ مشفّرة (%2e%2e، ..%2f، %2e%2e%2f) أو مسارات مطلقة.| التاريخ | الحدث |
|---|---|
| 2026-03-17 | اكتُشفت الثغرة أثناء بحث أمني على نسخة إنتاج منصوبة. |
| 2026-03-19 | أُرسل طلب CVE إلى MITRE. |
| 2026-05-07 | تم تعيين CVE-2026-38360 بواسطة MITRE. |
| 2026-05-07 | نُشرت النشرة الأمنية العامة. |
| 2026-05-09 | نُشر سجل CVE في قاعدة بيانات CVE التابعة لـ MITRE و NVD. |
0.6.1 (السلسلة المستقرة). الإصدارات الأولية (pre-releases) تمتد إلى 0.7.0a2.dash. الاعتماد الاختياري: pyyaml. الرخصة: MIT.Muhammad Fitri Bin Mohd Sultan