
إثبات مفهوم لـ CVE-2026-40864: تجاوز XSRF في JupyterHub عبر POST نموذج من أصل مختلف يستغل Sec-Fetch-Mode: no-cors. يتضمن HTML لإثبات المفهوم، وتحليل السبب الجذري، والجدول الزمني للإفصاح.
Sec-Fetch-Mode: no-cors)الخطورة: متوسطة (CVSS 5.4)
CWE: CWE-352 — تزوير الطلبات عبر المواقع (XSRF)
المتأثر: jupyterhub 4.1.0 ≤ الإصدار < 5.4.5 (تم إصلاحه في 5.4.5)
الاستشارة: GHSA-m68r-v472-jgq9
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-40864
الفضل: Romain Deperne
استخدمت حماية XSRF في JupyterHub (التي أُعيدت صياغتها في 4.1.0) ترويسة الطلب Sec-Fetch-Mode لتحديد
ما إذا كان الطلب من نفس الأصل. وقد اعتبرت Sec-Fetch-Mode: no-cors كأنه من نفس الأصل — لكن
no-cors هو بالضبط ما يرسله المتصفح عند إرسال نموذج "بسيط" من أصل مختلف. ونتيجةً لذلك،
تجاوزت طلبات POST عبر نماذج HTML من أصول مختلفة إلى نقاط نهاية النماذج في الـ Hub (/hub/spawn، /hub/accept-share)
فحص XSRF بالكامل.
واجهة JSON API غير متأثرة (فهي تتطلب نوع محتوى غير بسيط، مما يفرض فحصاً مسبقاً من CORS). فقط نقاط نهاية نماذج HTML يمكن الوصول إليها بهذه الطريقة.
تُقصّر منطق XSRF إلى "موثوق" لمجموعة من حالات Sec-Fetch-* المقصود منها التقاط
التنقلات من نفس الأصل. وقد أُدرجت Sec-Fetch-Mode: no-cors ضمن تلك المجموعة الموثوقة. لكن no-cors
هو النمط الذي يخصصه المتصفح لـ <form method=POST> عادي يُرسل إلى أصل مختلف —
وهو تحديداً ناقل CSRF الكلاسيكي الذي يُفترض أن يمنعه الرمز المميز. لذا فإن أي نقطة نهاية تُغيّر الحالة
وتقبل جسم نموذج بسيط، وتعتمد فقط على بوابة XSRF هذه، قابلة للتزوير من أصل مختلف.
وبتطبيق ذلك على نقاط النهاية الفعلية: /hub/spawn (تشغيل خادم الضحية) و/hub/accept-share
(جعل الضحية يقبل مشاركة خادم المهاجم) كلاهما طلبات POST عبر نماذج خلف هذه البوابة.
/hub/spawn — يمكن لصفحة المهاجم تشغيل خادم المستخدم الواحد الخاص بالضحية دون موافقة
(استهلاك موارد / حالة غير متوقعة؛ لا يحصل المهاجم على وصول إلى ذلك الخادم)./hub/accept-share — عندما يكون المهاجم مستخدماً في JupyterHub مسموحاً له بمشاركة خادمه
الخاص، يمكنه إجبار الضحية على قبول مشاركة، مما يمنح الضحية وصولاً إلى خادم المهاجم
(خطوة تحضيرية لسيناريوهات هندسة اجتماعية / إسقاط بيانات لاحقة).استخدام Sec-Fetch-Mode كمرجع لتحديد الأصل غير سليم: فـ no-cors لا يعني نفس الأصل. الإصلاح
في 5.4.5 يتوقف عن اعتبار no-cors كأنه من نفس الأصل. يمكن للمشغلين الذين لا يستطيعون الترقية فوراً
إسقاط الطلبات التي تحمل Sec-Fetch-Mode: no-cors على مستوى الوكيل العكسي.
poc/csrf_spawn.html — استضفه على أي أصل للمهاجم واجعل مستخدماً مسجّلاً في JupyterHub يفتحه.
يُصدر النموذج الذي يُرسل نفسه تلقائياً طلب POST من أصل مختلف إلى /hub/spawn (يرسل المتصفح
Sec-Fetch-Mode: no-cors)؛ تقبله الإصدارات المعرّضة دون رمز _xsrf صالح وتشغّل
خادم الضحية. وجّه action إلى /hub/accept-share للحصول على نسخة قبول المشاركة.
1. Edit TARGET-JUPYTERHUB in poc/csrf_spawn.html
2. Serve the file from an attacker origin (any static host)
3. Open it in a browser already authenticated to the target Hub
4. Observe the victim's server spawn with no XSRF token supplied
أُفصح عنه بمسؤولية. نُشر إثبات المفهوم بعد إصدار الإصلاح.