
Aviso y prueba de concepto de inyección de comandos del sistema operativo en un asistente ffmpeg de MCP, con análisis de causa raíz, orientación para detectores y mitigaciones para un paquete npm sin corregir.
runFFmpegCommand pasa una cadena construida a partir de los parámetros de la herramienta MCP a
spawn(…, { shell: true }), por lo que los metacaracteres de shell en options, format,
codec, pixelFormat o extraOptions se ejecutan en el host que ejecuta el servidor.
⚠ No existe una versión corregida
A fecha de 2026-08-22, la última versión publicada en npm es la 0.2.1, que es la versión afectada, y el sink sigue presente en la rama por defecto del repositorio. No hay nada a lo que actualizar. Consulta Mitigation para saber qué pueden hacer los usuarios mientras tanto.
Los argumentos de las herramientas MCP están influenciados por el atacante. Son producidos por un
LLM a partir del contenido que el agente procesa — documentos, páginas web, salida de herramientas —
por lo que la inyección indirecta de prompts pone al atacante en control de los valores que recibe un
manejador de herramientas. Un manejador que introduce cualquiera de esos valores en un shell convierte
esa influencia en ejecución de código en el host que ejecuta el servidor MCP. Este es el mismo modelo
que el caso precedente aws-mcp-server / CVE-2026-5058.
Un servidor de conversión de medios es un objetivo particularmente natural para esto: los archivos que se le pide procesar son exactamente el contenido no confiable que un agente recoge de otros lugares.
src/utils/ffmpeg.ts — el comando se ensambla como una cadena y el shell se habilita explícitamente:
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 }) ejecuta la cadena completa a través de
/bin/sh -c. Todo lo que el llamador aportó a command es sintaxis de shell.
src/tools/handlers.ts llega a ese helper desde tres herramientas, interpolando parámetros cuyo
contenido nunca se valida:
| Herramienta | Parámetros inyectables |
|---|---|
convert_video |
Solo se comprueban inputPath y outputPath, y los esquemas Zod validan el tipo (z.string()),
nunca el contenido — por lo que los metacaracteres pasan directamente.
Una llamada a convert_video con options establecido en ; touch /tmp/marker ; produce:
/bin/sh -c "ffmpeg -i /tmp/in.mp4 ; touch /tmp/marker ; /tmp/out.mp4"
poc/driver.mjs habla MCP sobre stdio: inicializa el servidor, emite una
tools/call para convert_video con un valor options inyectado y comprueba la existencia de un
archivo marcador. La carga útil es un touch benigno.
npm pack @sworddut/[email protected]
tar xf sworddut-mcp-ffmpeg-helper-0.2.1.tgz && cd package && npm install
node ../poc/driver.mjs
Resultado esperado en una versión afectada:
==== POC RESULT (@sworddut/mcp-ffmpeg-helper) ====
marker /tmp/PWNED_ffmpeg created: true
verdict: CONFIRMED — command injection executed
No es necesario que ffmpeg esté instalado — el comando inyectado se ejecuta en la misma cadena
/bin/sh -c independientemente de si el binario inicial se resuelve. Validado el 2026-06-01 en un
contenedor aislado, revalidado el 2026-06-13, y el sink se re-confirmó presente en la rama por
defecto el 2026-08-22. Ejecútalo solo contra infraestructura que estés autorizado a probar.
ffmpeg que contenga ;, &&, ||, |, una comilla invertida o $(.
Las invocaciones legítimas de ffmpeg de este servidor no las contienen.sh -c cuya línea de comandos comience con ffmpeg y contenga un segundo comando
después de un separador — una señal de árbol de procesos (auditd, eBPF, Falco, EDR) que no depende
del registro de la aplicación.ffmpeg y ffprobe son esperados; un shell, un
intérprete o un cliente de red no lo son.Running FFmpeg command: ffmpeg <command>,
que es el lugar más barato para detectar un valor inyectado si los registros se recopilan.options, , , o
contengan metacaracteres de shell.MITRE ATT&CK T1059.004 Intérprete de comandos y scripts: Shell Unix.
No existe una versión parcheada, por lo que las opciones son contención y eliminación:
runFFmpegCommand.La corrección upstream es eliminar shell: true y pasar a ffmpeg un vector de argumentos —
spawn("ffmpeg", ["-i", inputPath, …]) — construyendo ese array a partir de valores format,
codec y pixelFormat de una lista permitida en lugar de cadenas de formato libre. La validación
de contenido, no solo la validación de tipos de Zod, es el requisito subyacente.
NIST SP 800-53r5 SI-10; OWASP ASVS v4 §5.3.8; mitigaciones M1 y M2 de CWE-78.
aws-mcp-server)Avisos complementarios de la misma pasada de investigación: CVE-2026-52616, CVE-2026-52618.
MIT — consulta LICENSE.
| CVE | CVE-2026-52617 |
| CWE | CWE-78 (Neutralización incorrecta de elementos especiales usados en un comando del sistema operativo) |
| Paquete | @sworddut/mcp-ffmpeg-helper (npm) |
| Afectadas | 0.2.1 y anteriores — todas las versiones publicadas |
| Corregida en | ninguna |
| CVSS v3.1 | AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 7.8 Alta (transporte stdio). AV:N → 9.8 Crítica si el servidor está envuelto en un transporte de red. |
| Reportado por | s1ko (github.com/s1ko, [email protected]) |
| CVE asignado | 2026-07-13, MITRE CNA-LR |
options |
extract_audio | format |
create_video_from_images | codec, pixelFormat, extraOptions |
formatcodecpixelFormatextraOptions| Fecha | Evento |
|---|
| 2026-05-29 | Vulnerabilidad identificada mediante revisión del código fuente del tarball publicado |
| 2026-06-01 | Validada dinámicamente a través de MCP stdio en un contenedor aislado |
| 2026-06-13 | Revalidada en un segundo host; el repositorio no tiene habilitado el Private Vulnerability Reporting, y los campos repository/bugs/homepage de package.json se dejan en la plantilla github.com/yourusername, sin dejar un contacto de seguridad documentado |
| 2026-07-13 | MITRE CNA-LR asigna CVE-2026-52617, dando crédito a s1ko como descubridor |
| 2026-08-22 | Sink re-confirmado en la rama por defecto; npm latest todavía 0.2.1; este informe publicado |