
استشارة أمنية وإثبات مفهوم لثغرة حقن أوامر نظام التشغيل في أداة مساعدة ffmpeg لـ MCP، مع تحليل السبب الجذري وإرشادات الكشف وإجراءات التخفيف لحزمة npm غير مصححة.
تمرّر runFFmpegCommand سلسلة نصية مبنية من معاملات أداة MCP إلى
spawn(…, { shell: true })، لذا تُنفَّذ الأحرف الخاصة بالصدفة (shell metacharacters) في options أو format
أو codec أو pixelFormat أو extraOptions على المضيف الذي يشغّل الخادم.
⚠ لا يوجد إصدار مُصلَّح
حتى تاريخ 2026-08-22، أحدث إصدار على npm هو 0.2.1، وهو الإصدار المتأثر، ولا يزال موضع الخلل (sink) موجودًا في الفرع الافتراضي للمستودع. لا يوجد إصدار يمكن الترقية إليه. راجع التخفيف لمعرفة ما يمكن للمستخدمين فعله في هذه الأثناء.
| CVE | CVE-2026-52617 |
| CWE | CWE-78 (عدم تحييد العناصر الخاصة المستخدمة في أمر نظام التشغيل بشكل صحيح) |
| الحزمة | @sworddut/mcp-ffmpeg-helper (npm) |
| المتأثر | 0.2.1 وما قبله — جميع الإصدارات المنشورة |
| مُصلَّح في | لا شيء |
| CVSS v3.1 | AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 8.4 High (نقل stdio). AV:N → 9.8 Critical إذا كان الخادم مغلّفًا بنقل شبكي. |
| أبلغ عنه | s1ko (github.com/s1ko، [email protected]) |
| تاريخ تعيين CVE | 2026-07-13، MITRE CNA-LR |
معاملات أداة MCP قابلة للتأثير من المهاجم. فهي تُنتَج بواسطة نموذج لغوي كبير (LLM) من
المحتوى الذي يعالجه الوكيل — مستندات، صفحات ويب، مخرجات أدوات — لذا فإن حقن الأوامر غير المباشر (indirect prompt injection) يمنح المهاجم السيطرة على القيم التي يتلقاها
معالج الأداة. وأي معالج يمرّر أيًّا من تلك القيم إلى صدفة (shell) يحوّل
ذلك التأثير إلى تنفيذ تعليمات برمجية على المضيف الذي يشغّل خادم MCP. هذا هو
النموذج نفسه المتبع في الحالة السابقة aws-mcp-server / CVE-2026-5058.
خادم تحويل الوسائط هدف طبيعي بشكل خاص لهذا النوع من الهجمات: فالملفات التي يُطلب منه معالجتها هي بالضبط المحتوى غير الموثوق الذي يلتقطه الوكيل من مكان آخر.
src/utils/ffmpeg.ts — يُجمَّع الأمر كسلسلة نصية وتُفعَّل الصدفة
صراحةً:
function runProcess(command: string, args: string[], useShell = false) {
const child = spawn(command, args, { shell: useShell, windowsHide: true });
…
}
export async function runFFmpegCommand(command: string): Promise<string> {
const { stdout, stderr, code } = await runProcess(`ffmpeg ${command}`, [], true);
…
}
spawn("ffmpeg " + command, [], { shell: true }) يمرر السلسلة بأكملها عبر
/bin/sh -c. كل ما ساهم به المستدعي في command هو صيغة shell.
يصل src/tools/handlers.ts إلى ذلك المساعد من ثلاث أدوات، مع إدراج
معاملات لا يتم التحقق من محتواها أبدًا:
| الأداة | المعاملات القابلة للحقن |
|---|---|
convert_video | options |
extract_audio | format |
create_video_from_images | codec، pixelFormat، extraOptions |
يتم التحقق من inputPath وoutputPath فقط على الإطلاق، ومخططات Zod
تتحقق من النوع (z.string())، وليس من المحتوى أبدًا — لذا تمر الأحرف الخاصة
مباشرة.
استدعاء convert_video مع تعيين options إلى ; touch /tmp/marker ; ينتج:
/bin/sh -c "ffmpeg -i /tmp/in.mp4 ; touch /tmp/marker ; /tmp/out.mp4"
poc/driver.mjs يتحدث MCP عبر stdio: يهيّئ الخادم، ويصدر استدعاءً واحدًا tools/call لـ convert_video بقيمة options مُحقَنة، ويتحقق من وجود ملف علامة. الحمولة هي touch غير ضار.
npm pack @sworddut/[email protected]
tar xf sworddut-mcp-ffmpeg-helper-0.2.1.tgz && cd package && npm install
node ../poc/driver.mjs
متوقع على إصدار مصاب:
==== POC RESULT (@sworddut/mcp-ffmpeg-helper) ====
marker /tmp/PWNED_ffmpeg created: true
verdict: CONFIRMED — command injection executed
لا حاجة لتثبيت ffmpeg — فالأمر المحقون يعمل داخل نفس سلسلة
/bin/sh -c بغض النظر عمّا إذا كان الملف التنفيذي الأولي قابلًا للحل أم لا.
تم التحقق منه في 2026-06-01 داخل حاوية معزولة، وأُعيد التحقق منه في 2026-06-13، وأُعيد
تأكيد وجود نقطة الحقن على الفرع الافتراضي في 2026-08-22. لا تشغّله إلا
على البنية التحتية المصرّح لك باختبارها.
ffmpeg يحتوي على ; أو && أو || أو | أو علامة backtick أو $(.
استدعاءات ffmpeg المشروعة من هذا الخادم لا تحتوي على ذلك.sh -c يبدأ سطر أوامرها بـ ffmpeg وتحتوي على
أمر ثانٍ بعد فاصل — إشارة على مستوى شجرة العمليات (auditd، eBPF،
Falco، EDR) لا تعتمد على تسجيل التطبيق.ffmpeg وffprobe؛
أما وجود shell أو مفسّر أو عميل شبكة فليس متوقعًا.Running FFmpeg command: ffmpeg <command>، وهو أرخص مكان
لرصد قيمة محقونة إذا كانت السجلات تُجمَع أصلًا.options أو format أو codec أو pixelFormat أو
extraOptions على محارف meta الخاصة بالـ shell.MITRE ATT&CK T1059.004 Command and Scripting Interpreter: Unix Shell.
لا يوجد إصدار مُرقَّع، لذا فالخيارات هي الاحتواء والإزالة:
runFFmpegCommand.الإصلاح في المنبع هو إسقاط shell: true وتمرير متجه معاملات إلى ffmpeg
— spawn("ffmpeg", ["-i", inputPath, …]) — وبناء ذلك المصفوفة من
قيم format وcodec وpixelFormat المدرجة في قائمة السماح بدلًا من
سلاسل حرة الشكل. التحقق من المحتوى، وليس مجرد التحقق من النوع عبر Zod، هو
المتطلب الأساسي.
NIST SP 800-53r5 SI-10؛ OWASP ASVS v4 §5.3.8؛ تخفيفات CWE-78 M1 وM2.
| التاريخ | الحدث |
|---|---|
| 2026-05-29 | تحديد الثغرة عبر مراجعة مصدر حزمة tarball المنشورة |
| 2026-06-01 | التحقق الديناميكي عبر MCP stdio في حاوية معزولة |
| 2026-06-13 | إعادة التحقق على مضيف ثانٍ؛ المستودع لا يفعّل Private Vulnerability Reporting، وحقول repository/bugs/homepage في package.json متروكة على قالب github.com/yourusername، ما يتركه بلا جهة اتصال أمنية موثّقة |
| 2026-07-13 | يخصّص MITRE CNA-LR المعرّف CVE-2026-52617، مع نسبة الاكتشاف إلى s1ko |
| 2026-08-22 | إعادة تأكيد نقطة الحقن على الفرع الافتراضي؛ أحدث إصدار على npm لا يزال 0.2.1؛ نشر هذا التقرير |
aws-mcp-server)تنبيهات مرافقة من نفس جولة البحث: CVE-2026-52616، CVE-2026-52618.
MIT — انظر LICENSE.