
إثبات المفهوم (PoC) لـ CVE-2026-18953 — كتابة ملف تعسفية (CWE-22) في أداة get_resource الخاصة بـ awslabs.aws-transform-mcp-server عبر معامل savePath
| CVE | CVE-2026-18953 |
| CWE | CWE-22 — تقييد غير سليم لاسم المسار داخل دليل مقيد |
| المتأثر | awslabs.aws-transform-mcp-server 0.1.0 – 0.1.4 |
| أُصلح في | 0.1.5 |
| CVSS v3.1 | 8.6 عالٍ — AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H |
| CVSS v4.0 | 6.3 متوسط — AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:H/SA:H |
| الإشعار الأمني | GHSA-66mr-jr63-2jgw |
| النشرة الأمنية | AWS Security Bulletin 2026-075 |
| المبلِّغ | Drew Raines (إفصاح منسّق) |
| نُشر | 2026-08-05 |
get_resource(resource="artifact" | "asset", ...) تنزّل ملفًا من عنوان S3 مُوقَّع مسبقًا، وعندما يمرر المتصل savePath / fileName، تحفظه على القرص المحلي عبر:
tools/get_resource.py -> tool_utils.download_s3_content()
-> file_validation.validate_write_path()
في <= 0.1.4، تقوم validate_write_path() فقط بـ:
save_path باستخدام os.path.realpath(os.path.expanduser(...)).~/.aws, ~/.ssh, ~/.gnupg, ~/.docker, ~/.aws-transform-mcp, /etc/shadow, /etc/passwd).file_name عبر os.path.basename().إنها لا تحصر الدليل المُحلَّل في أي دليل أساسي/دليل عمل، وBLOCKED_FILENAMES (.bashrc, .zshrc, authorized_keys, id_rsa, …) يُطبَّق على القراءات فقط، لا على الكتابات. لذلك يمكن لأي عميل MCP لهذا الخادم — بما في ذلك وكيل تم حقن تلقينه بشكل غير مباشر عبر محتوى وظائف/مهام/رسائل غير موثوق يجلبه من خلال هذه الأداة نفسها — تعيين savePath إلى مسار مطلق، أو اجتياز ../..، أو اسم ملف نقطي حساس، فيكتب الخادم وحدات بايت متأثرة بالمهاجم هناك. هذه بدائية كتابة ملفات خارج الدليل الذي يعتقد المشغِّل أن التنزيلات محصورة فيه؛ ويشير الإشعار إلى أنها «قد تؤدي إلى تنفيذ تعليمات برمجية محليًا» (مثل الكتابة فوق ملف بدء تشغيل الصدفة).
يصلح الإصدار 0.1.5 هذا الأمر بإضافة دليل أساسي صريح في القائمة المسموح بها (_ALLOWED_WRITE_BASE، مأخوذ من $AWS_TRANSFORM_MCP_WRITE_DIR أو من CWD للخادم عند بدء التشغيل) يجب أن يقع كل مسار كتابة مُحلَّل ضمنه، وكذلك بتطبيق BLOCKED_FILENAMES على مسار الكتابة المُحلَّل النهائي.
الفرق الكامل للسبب الجذري: vendor/0.1.4-vulnerable/file_validation.py مقابل vendor/0.1.5-fixed/file_validation.py (كلاهما منسوخ حرفيًا من PyPI / GitHub، بموجب Apache-2.0).
يصدر عميل MCP (Q Developer، Kiro، Claude، وغيرها موصولة بهذا الخادم) استدعاء أداة مثل:
{
"name": "get_resource",
"arguments": {
"resource": "artifact",
"workspaceId": "ws-...",
"jobId": "job-...",
"artifactId": "art-...",
"savePath": "/Users/victim/Library/LaunchAgents",
"fileName": "com.evil.persist.plist"
}
}
أو، من دليل عزل (sandbox) نسبي:
{ "savePath": "../../../../../../Users/victim/.bashrc", "fileName": "x" }
نظرًا لأن الأداة تصف استجابات resource="task" على أنها أشياء يجب على الوكيل قراءتها والتصرف بناءً عليها، ومحتوى resource="messages" ينشأ من بيانات الدردشة/الوظائف، فإن أحد المتعاونين في مساحة العمل (أو مصدر upstream مخترق للوظائف/الرسائل) لا يحتاج إلى إقناع إنسان بكتابة هذا — يكفي توجيه وكيل متصل بالفعل إلى استدعاء get_resource مع savePath عدائي. لا حاجة إلى بيانات اعتماد AWS حقيقية لإظهار الثغرة نفسها، لأن الخلل بأكمله في معالجة المسار المحلي، قبل/بعد جلب S3.
python3 poc.py
لا تبعيات خارجية، ولا حساب AWS، ولا وصول شبكي إلى AWS. يقوم السكربت بـ:
file_validation.py الحقيقي وغير المعدَّل من كل من 0.1.4 و0.1.5+ (انظر vendor/).download_s3_content() بنفس تدفق التحكم تمامًا من tool_utils.py الأصلي (مع استبدال httpx بـ urllib من المكتبة القياسية فقط — صفر تبعيات، نفس المنطق)، وقيادتها تمامًا كما تفعل get_resource.savePath/fileName — هروب بمسار مطلق، واجتياز نسبي ../..، واسم ملف نقطي محظور على القراءات فقط — ضد المدقق المعرّض للثغرة، ثم ضد المدقق المُصلَح.كل شيء يحدث داخل دليل مؤقت mkdtemp()؛ ولا يتم لمس $HOME الحقيقي أبدًا. مخرجات نموذجية:
=== Target: file_validation.py from 0.1.4-vulnerable ===
-> Absolute path escape (no traversal needed at all)
RESULT: VULNERABLE: wrote OUTSIDE sandbox -> .../outside_sandbox/dropped_by_absolute_path.sh
-> Relative "../../.." traversal out of the sandbox dir
RESULT: VULNERABLE: wrote OUTSIDE sandbox -> .../outside_sandbox/dropped_by_traversal.sh
-> Sensitive dotfile name, written inside a decoy $HOME
RESULT: VULNERABLE: wrote OUTSIDE sandbox -> .../outside_sandbox/decoy_home/.bashrc
=== Target: file_validation.py from 0.1.5-fixed ===
-> Absolute path escape (no traversal needed at all)
RESULT: BLOCKED (raised ValueError): Write path must be within the working directory (...)
-> Relative "../../.." traversal out of the sandbox dir
RESULT: BLOCKED (raised ValueError): ...
-> Sensitive dotfile name, written inside a decoy $HOME
RESULT: BLOCKED (raised ValueError): ...
قم بالترقية إلى awslabs.aws-transform-mcp-server >= 0.1.5. لا يوجد حل بديل على جانب الخادم للإصدارات الأقدم؛ يوصي الإشعار بالترقية. يجب على المشغِّلين الذين لا يستطيعون الترقية فورًا تشغيل الخادم مع ضبط CWD على دليل مخصص وفارغ، والتعامل مع أي ملف يمكنه الكتابة إليه باعتباره مخترقًا.
README.md — this file
poc.py — self-contained PoC driver
vendor/_loguru_shim.py — tiny stand-in for the `loguru` dep (test scaffolding only)
vendor/0.1.4-vulnerable/file_validation.py — real vulnerable source, from PyPI sdist
vendor/0.1.5-fixed/file_validation.py — real patched source, from github.com/awslabs/mcp@main