
مجموعة أدوات للكشف والاستغلال لثغرة CVE-2026-39987، وهي ثغرة تنفيذ تعليمات برمجية عن بُعد (RCE) قبل المصادقة في دفاتر Marimo. تتضمن ماسحًا بلغة Python وسكربت Nmap NSE لتحديد الحالات المعرضة للخطر عبر فحوصات نقطة نهاية WebSocket.
ثغرة تنفيذ تعليمات برمجية عن بُعد قبل المصادقة في Marimo، وهو دفتر ملاحظات Python مفتوح المصدر لعلوم البيانات والذكاء الاصطناعي/تعلّم الآلة. نقطة نهاية WebSocket الطرفية (/terminal/ws) تتجاوز التحقق من المصادقة بالكامل، بينما نقطة نهاية دفتر الملاحظات المجاورة (/ws) تفرضها بشكل صحيح. يمكن لمهاجم غير مصادق الاتصال بـ /terminal/ws والحصول على صدفة PTY تفاعلية كاملة على النظام المضيف بدون أي بيانات اعتماد.
تم استغلالها في البرية خلال 10 ساعات من الإفصاح عنها. سرق المهاجمون بيانات اعتماد AWS في أقل من 3 دقائق.
تؤثر على Marimo <= 0.20.4. تم إصلاحها في Marimo 0.23.0.
| الحقل | التفاصيل |
|---|---|
| معرف CVE | CVE-2026-39987 |
| البائع | مشروع Marimo |
| المنتج | Marimo (دفتر ملاحظات Python) |
| الإصدارات المتأثرة | <= 0.20.4 |
| CVSS v3.1 | 9.3 (حرجة) |
| CWE | CWE-306 — غياب المصادقة لوظيفة حرجة |
| متجه الهجوم | الشبكة |
| المصادقة | غير مطلوبة |
| تفاعل المستخدم | لا شيء |
| نضج الاستغلال | مستغلة بنشاط في البرية |
| الوقت حتى الاستغلال | ~10 ساعات بعد الإفصاح |
| تم إصلاحها في | Marimo 0.23.0 |
Marimo هو دفتر ملاحظات Python تفاعلي مفتوح المصدر مصمم كبديل حديث لـ Jupyter. وهو مبني لعلوم البيانات، وتجارب الذكاء الاصطناعي/تعلّم الآلة، وتحليل البيانات التفاعلي. تشمل ميزاته الرئيسية تتبع التبعيات تلقائيًا، والتنفيذ القابل للتكرار، وتجربة مطور أنظف مقارنة بدفاتر الملاحظات التقليدية.
يكتسب Marimo زخمًا سريعًا في مجتمع Python والذكاء الاصطناعي/تعلّم الآلة، خاصة بين الممارسين الذين يريدون سير عمل دفاتر ملاحظات أكثر تنظيماً مما يوفره Jupyter.
مثل جميع بيئات دفاتر الملاحظات، عادةً ما يكون لدى مثيلات Marimo وصول إلى موارد حساسة: بيانات اعتماد السحابة (AWS، GCP، Azure)، وسلاسل اتصال قواعد البيانات، ومفاتيح API لخدمات الذكاء الاصطناعي (OpenAI، Anthropic، وغيرها)، والوصول إلى الشبكة الداخلية. على عكس تطبيقات الويب التقليدية، تم تصميم دفاتر الملاحظات لتنفيذ تعليمات برمجية عشوائية. هذا هو غرضها الأساسي.
هذا المزيج يجعل أي تجاوز للمصادقة في بيئة دفتر ملاحظات مدمرًا بشكل خاص.``` Typical Marimo Deployment:
┌──────────────┐ ┌────────────────────────────────┐ │ │ HTTP │ Marimo Server │ │ Browser │────────>│ │ │ (User) │ │ ┌──────────────────────────┐ │ │ │<────────│ │ /ws (Notebook) │ │ └──────────────┘ WS │ │ ✅ validate_auth() │ │ │ └──────────────────────────┘ │ │ │ │ ┌──────────────────────────┐ │ │ │ /terminal/ws │ │ │ │ ❌ NO AUTH CHECK │ │ │ └──────────────────────────┘ │ │ │ │ ┌──────────────────────────┐ │ │ │ Python Environment │ │ │ │ .env files │ │ │ │ AWS credentials │ │ │ │ API keys │ │ │ └──────────────────────────┘ │ └────────────────────────────────┘
---
## الغوص العميق في الثغرة
### نقطتا نهاية WebSocket
ينفّذ خادم Marimo نقاط نهاية WebSocket متعددة لميزات مختلفة. الفرق الحاسم بين نقطتي النهاية الرئيسيتين هو وجود (أو غياب) فحص المصادقة:```
Authentication Flow Comparison:
/ws (Notebook WebSocket):
┌─────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────┐
│ Connect │───>│ validate_auth │───>│ Accept │───>│ Notebook │
└─────────┘ └───────┬───────┘ └──────────┘ └───────────┘
│
❌ Reject if
not authenticated
/terminal/ws (Terminal WebSocket):
┌─────────┐ ┌───────────────┐ ┌──────────┐ ┌───────────┐
│ Connect │───>│ Check mode & │───>│ Accept │───>│ PTY Shell │
└─────────┘ │ platform only │ └──────────┘ └───────────┘
└───────────────┘
⚠️ No auth check!
Anyone gets a shell!
نقطة نهاية دفتر الملاحظات (/ws) تستدعي بشكل صحيح validate_auth() للتحقق من هوية المستخدم قبل قبول اتصالات WebSocket. هذا هو السلوك الأمني المتوقع.
نقطة نهاية الطرفية (/terminal/ws) تتحقق فقط مما إذا كان الخادم في وضع التشغيل وما إذا كانت المنصة تدعم وظيفة الطرفية. إنها لا تستدعي أبدًا validate_auth(). بعد اجتياز هذه الفحوصات الأساسية، تقبل الاتصال وتنشئ جلسة PTY (طرفية زائفة) كاملة.```python
async def websocket_connect(self, message): await self.validate_auth() # ✅ Checks authentication await self.accept() # ... notebook communication
async def websocket_connect(self, message): if not self.is_running_mode(): # Only checks mode await self.close() return if not self.is_platform_supported(): # Only checks platform await self.close() return await self.accept() # ❌ No auth! Anyone gets a shell # ... PTY shell creation
هذا هو **CWE-306: Missing Authentication for Critical Function** (غياب المصادقة للوظائف الحرجة). أخطر نقطة نهاية على الخادم (تلك التي توفر قشرة تفاعلية) لا تحتوي على أي مصادقة على الإطلاق.
### الهجوم: من الاستشارة إلى مفاتيح AWS في 3 دقائق
يوضح الجدول الزمني للاستغلال مدى سرعة عمل الجهات الفاعلة في التهديدات الحديثة:```
┌──────────────────────────────────────────────────────────────┐
│ CVE-2026-39987 Timeline │
├──────────────────────────────────────────────────────────────┤
│ │
│ T+0h Advisory published │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ T+9h First exploit built from advisory │
│ T+10h Exploitation in the wild confirmed │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ T+10h 0m Attacker connects to /terminal/ws │
│ T+10h 1m Full PTY shell obtained │
│ T+10h 2m .env file located and read │
│ T+10h 3m AWS keys exfiltrated │
│ Total attack time: ~3 minutes │
└──────────────────────────────────────────────────────────────┘
الهجوم نفسه بسيط للغاية:``` Step 1: Attacker opens WebSocket connection to /terminal/ws (No authentication needed, no special tools required)
Step 2: Server creates a PTY (pseudo-terminal) session Attacker now has an interactive shell
Step 3: Attacker runs commands: $ cat .env AWS_ACCESS_KEY_ID=AKIA... AWS_SECRET_ACCESS_KEY=... DATABASE_URL=postgres://... OPENAI_API_KEY=sk-...
Step 4: Credentials exfiltrated Attacker now has cloud access, database access, and API keys for AI services
Total time: under 3 minutes Authentication required: none Tools required: any WebSocket client
لا حاجة لتطوير استغلال. لا شيلكود. لا تلف في الذاكرة. فقط عميل WebSocket وفحص مصادقة مفقود.
---
## تحليل التأثير
**التأثير المباشر على مضيف Marimo:**
- غلاف تفاعلي كامل بصلاحيات عملية Marimo
- الوصول إلى جميع الملفات القابلة للقراءة من قبل العملية (الكود المصدري، البيانات، بيانات الاعتماد)
- الوصول إلى متغيرات البيئة التي تحتوي على مفاتيح API والأسرار
- القدرة على تنفيذ أوامر عشوائية على النظام المضيف
**كشف بيانات الاعتماد (الهدف الهجومي الأساسي):**
- مفاتيح الوصول والمفاتيح السرية لـ AWS من ملفات `.env` أو متغيرات البيئة
- بيانات اعتماد حسابات الخدمة في GCP/Azure
- سلاسل اتصال قواعد البيانات مع كلمات المرور
- مفاتيح API لخدمات OpenAI وAnthropic وخدمات الذكاء الاصطناعي الأخرى
- مفاتيح SSH ومواد مصادقة أخرى
**التأثير اللاحق (عبر بيانات الاعتماد المسروقة):**
- وصول غير مصرح به إلى البنية التحتية السحابية (EC2، S3، Lambda، إلخ)
- تسريب البيانات من التخزين السحابي وقواعد البيانات
- إساءة استخدام الموارد (تعدين العملات الرقمية، سرقة أرصدة API للذكاء الاصطناعي)
- حركة جانبية إلى الشبكات السحابية والشبكات المحلية
**عوامل تضخيم المخاطر:**
- بيئات الدفاتر مصممة لتنفيذ كود عشوائي (هذا هو الغرض منها)
- بيئات علوم البيانات عادةً ما تمتلك وصولاً سحابياً واسعاً لمهام التدريب
- العديد من حالات Marimo معرّضة للإنترنت للتعاون والعمل عن بُعد
- تقوية الأمان غالباً ما تكون فكرة لاحقة في بيئات البحث/التجريب
---
## الإصدارات المتأثرة
| الإصدار | الحالة |
|---------|--------|
| Marimo 0.23.0+ | **تم التصحيح** |
| Marimo 0.20.5 إلى 0.22.x | **على الأرجح عرضة للخطر** (بين نطاق الاستشارة والإصلاح) |
| Marimo <= 0.20.4 | **عرضة للخطر** (النطاق المؤكد) |
---
## الصورة الأكبر: سلسلة أدوات الذكاء الاصطناعي/التعلم الآلي تحت الهجوم
CVE-2026-39987 ليست حادثة معزولة. إنها جزء من نمط واضح ظهر في أبريل 2026:
| CVE | المنتج | النوع | الحالة |
|:---|:---|:---|:---|
| **CVE-2026-39987** | Marimo | RCE قبل المصادقة (WebSocket) | تم استغلاله خلال 10 ساعات |
| **CVE-2026-33017** | Langflow | RCE | CISA KEV (26 مارس) |
| **CVE-2026-5059** | aws-mcp-server | حقن أوامر RCE | استشارة عامة |
| **TorchGeo** | TorchGeo | eval() RCE | استشارة عامة |
أربع أدوات تطوير للذكاء الاصطناعي/التعلم الآلي تعرضت لثغرات RCE حرجة في شهر واحد. خط أنابيب تطوير الذكاء الاصطناعي/التعلم الآلي أصبح تقنية الظل الجديدة: أدوات تُنشر بوصول واسع، وإشراف أمني ضئيل، ومخازن بيانات اعتماد غنية.```
┌─────────────────────────────────────────────────┐
│ Why AI/ML Tools Are Prime Targets │
├─────────────────────────────────────────────────┤
│ │
│ 1. DESIGNED to execute arbitrary code │
│ (that's literally what notebooks do) │
│ │
│ 2. Run with elevated privileges │
│ (GPU access, cloud SDKs, network access) │
│ │
│ 3. Contain high-value credentials │
│ (AWS keys, API tokens, DB connections) │
│ │
│ 4. Often exposed to the network │
│ (for collaboration and remote access) │
│ │
│ 5. Security hardening is an afterthought │
│ (focus on features and UX, not security) │
│ │
│ 6. Users are researchers, not security experts │
│ (default configs, weak passwords, no VPN) │
└─────────────────────────────────────────────────┘
يكتشف السكربت المكتوب بلغة بايثون حالات Marimo الضعيفة من خلال تحليل متعدد الخطوات.
كيف يعمل:
/api/status و /api/health و / للبحث عن مؤشرات Marimo في محتوى الاستجابات والترويسات/terminal/ws (بدون إرسال أي بيانات عبر الاتصال)/terminal/ws (يجب أن يتطلب مصادقة) مقابل /ws (المعروف أنه يتطلب مصادقة) لتأكيد عدم الاتساقلا يتم تنفيذ أي أوامر على الأنظمة المستهدفة. يتم اختبار مصافحة WebSocket ولكن لا يتم إرسال أي بيانات عبر الاتصال. الفحص سلبي بالكامل وآمن لبيئات الإنتاج.
الاستخدام:```bash
pip install -r requirements.txt
python CVE-2026-39987_Marimo_RCE_detector.py -t http://marimo-host:2718
python CVE-2026-39987_Marimo_RCE_detector.py -t https://marimo-host:443
python CVE-2026-39987_Marimo_RCE_detector.py -f targets.txt -o results.json -v
python CVE-2026-39987_Marimo_RCE_detector.py -t http://10.0.0.5:2718 --timeout 15
**الخيارات:**
| العلم | الوصف | الافتراضي |
|------|-------------|---------|
| `-t`, `--target` | عنوان URL واحد مستهدف (مثل: `http://host:2718`) | — |
| `-f`, `--file` | ملف يحتوي على عناوين URL المستهدفة، سطر واحد لكل عنوان (التعليقات بـ `#` مدعومة) | — |
| `-o`, `--output` | حفظ النتائج في ملف JSON | — |
| `--timeout` | مهلة الاتصال بالثواني | `10` |
| `--verify-ssl` | تفعيل التحقق من شهادة SSL | معطّل |
| `-v`, `--verbose` | إخراج مفصّل مع كامل التفاصيل | إيقاف |
**مثال على الإخراج:**```
[*] CVE-2026-39987 Marimo Pre-Auth RCE Scanner
[*] Scanning 1 target(s)...
[*] NOTE: This scanner only checks for endpoint exposure.
[*] No commands are executed on target systems.
======================================================================
Target: http://10.0.0.5:2718
Scan Time: 2026-04-14T16:00:00Z
Risk Level: CRITICAL
======================================================================
Is Marimo: YES
Marimo Version: 0.19.2
/terminal/ws Open: YES — UNAUTHENTICATED
Vulnerable: YES
*** CRITICAL: Pre-authenticated RCE is possible! ***
*** An attacker can get a full PTY shell without any auth ***
Details:
- Marimo instance detected via /api/status
- Marimo version: 0.19.2
- WebSocket upgrade accepted — /terminal/ws accessible WITHOUT auth
- CONFIRMED: /terminal/ws accepts unauthenticated connections while
/ws requires auth — classic CVE-2026-39987 signature
- Version 0.19.2 <= 0.20.4 — VULNERABLE to pre-auth RCE
======================================================================
[*] Scan Complete: 1 targets scanned
[*] Marimo Instances: 1 | Vulnerable: 1 | Critical: 1
======================================================================
sudo cp CVE-2026-39987_Marimo_RCE.nse /usr/share/nmap/scripts/ sudo nmap --script-updatedb
nmap -p 2718 --script CVE-2026-39987_Marimo_RCE
nmap -p 2718,8080,8443,443 --script CVE-2026-39987_Marimo_RCE
nmap -p 2718 --script CVE-2026-39987_Marimo_RCE 10.0.0.0/24
nmap -p 2718 --script CVE-2026-39987_Marimo_RCE -iL targets.txt
nmap -sV -p 2718 --script CVE-2026-39987_Marimo_RCE
**مثال على مخرجات Nmap:**```
PORT STATE SERVICE
2718/tcp open http
| CVE-2026-39987_Marimo_RCE:
| VULNERABLE:
| Marimo Pre-Auth RCE (CVE-2026-39987)
| State: VULNERABLE
| Risk level: CRITICAL
| Marimo Version: 0.19.2
| /terminal/ws: accessible without authentication
| Description:
| The Marimo /terminal/ws WebSocket endpoint accepts connections
| without authentication, enabling pre-authenticated RCE.
| An attacker can obtain a full PTY shell without any credentials.
| References:
|_ https://nvd.nist.gov/vuln/detail/CVE-2026-39987
إذا كان لديك وصول إلى مثيل Marimo:```bash
curl -s http://:2718/api/status | python3 -m json.tool
curl -s -o /dev/null -w "%{http_code}"
-H "Upgrade: websocket"
-H "Connection: Upgrade"
-H "Sec-WebSocket-Key: dGVzdC1rZXktMTIzNDU2Nzg="
-H "Sec-WebSocket-Version: 13"
http://:2718/terminal/ws
curl -s -o /dev/null -w "%{http_code}"
-H "Upgrade: websocket"
-H "Connection: Upgrade"
-H "Sec-WebSocket-Key: dGVzdC1rZXktMTIzNDU2Nzg="
-H "Sec-WebSocket-Version: 13"
http://:2718/ws
إذا كان `/terminal/ws` يُرجع 101 بينما يُرجع `/ws` 401/403، فهذه هي البصمة الكلاسيكية لثغرة CVE-2026-39987.
---
## مؤشرات الاختراق
راقب هذه العلامات في بيئتك:
| المؤشر | أين تتحقق | ما الذي تبحث عنه |
|:---|:---|:---|
| اتصالات WebSocket غير المصرح بها | سجلات الخادم/الوكيل | اتصالات بـ `/terminal/ws` من عناوين IP غير متوقعة |
| إنشاء جلسات PTY | مراقبة العمليات | عمليات shell غير متوقعة تم إنشاؤها بواسطة خادم Marimo |
| الوصول إلى الملفات | سجلات تدقيق الملفات | قراءات لملفات `.env` أو ملفات الاعتمادات أو مفاتيح SSH |
| استخدام الاعتمادات | سجلات تدقيق مزود السحابة | استدعاءات API تستخدم مفاتيح تم تخزينها في بيئة Marimo |
| نقل البيانات الصادر | مراقبة الشبكة | حركة مرور صادرة غير معتادة من مضيف Marimo |
**أوامر التحقيق:**```bash
# Check for active WebSocket connections
ss -tnp | grep <MARIMO_PORT>
# Review process tree for unexpected shells
ps aux --forest | grep -A5 marimo
# Check if .env or credential files were recently accessed
stat .env
stat ~/.aws/credentials
# Review cloud provider activity logs for unauthorized access
aws cloudtrail lookup-events --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=<KEY_ID>
# Check for unauthorized outbound connections
netstat -tnp | grep ESTABLISHED | grep -v 127.0.0.1
إجراءات فورية (قم بها الآن):
pip install --upgrade marimo)على المدى القصير (خلال هذا الأسبوع):
.env ومتغيرات البيئة بحثًا عن أي بيانات حساسة قد تكون مكشوفةعلى المدى الطويل:
كيرم أوروتش — مهندس الأمن السيبراني