
수정되지 않은 npm 패키지의 MCP ffmpeg 헬퍼에서 발생하는 OS 명령어 주입에 대한 보안 권고 및 개념 증명(PoC)으로, 근본 원인 분석, 탐지 가이드, 완화 조치를 포함합니다.
runFFmpegCommand는 MCP 도구 매개변수로 구성된 문자열을 spawn(…, { shell: true })에 전달하므로, options, format, codec, pixelFormat 또는 extraOptions에 포함된 셸 메타문자가 서버를 실행 중인 호스트에서 실행됩니다.
⚠ 수정 버전 없음
2026-08-22 기준 최신 npm 릴리스는 0.2.1이며, 이 버전이 영향을 받는 버전이고, 싱크(sink)는 여전히 저장소의 기본 브랜치에 존재합니다. 업그레이드할 버전이 없습니다. 사용자가 그동안 할 수 있는 조치는 완화(Mitigation)를 참조하세요.
MCP 도구 인수는 공격자의 영향을 받습니다. 이러한 인수는 에이전트가 처리하는 콘텐츠(문서, 웹 페이지, 도구 출력)를 기반으로 LLM이 생성하므로, 간접 프롬프트 주입을 통해 공격자는 도구 핸들러가 수신하는 값을 제어할 수 있습니다. 이러한 값 중 하나라도 셸에 전달하는 핸들러는 그 영향력을 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에 넣은 모든 것은 셸 구문이 됩니다.
src/tools/handlers.ts는 세 가지 도구에서 해당 헬퍼에 도달하며, 콘텐츠에 대해 전혀 검증되지 않는 매개변수를 보간합니다:
| 도구 | 주입 가능한 매개변수 |
|---|---|
convert_video | options |
inputPath와 outputPath만 겨우 확인되며, Zod 스키마는 유형만 검증할 뿐(z.string()) 콘텐츠는 전혀 검증하지 않으므로 메타문자가 그대로 통과합니다.
options가 ; touch /tmp/marker ;로 설정된 convert_video 호출은 다음을 생성합니다:
/bin/sh -c "ffmpeg -i /tmp/in.mp4 ; touch /tmp/marker ; /tmp/out.mp4"
poc/driver.mjs는 stdio를 통해 MCP를 사용합니다. 서버를 초기화하고, 주입된 options 값으로 convert_video에 대한 tools/call을 한 번 실행한 다음 마커 파일이 있는지 확인합니다. 페이로드는 무해한 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에 기본 브랜치에 싱크(sink)가 여전히 존재함을 재확인했습니다. 테스트할 권한이 있는 인프라에서만 실행하세요.
;, &&, ||, |, 백틱 또는 $(를 포함하는 ffmpeg 명령줄. 이 서버의 정상적인 ffmpeg 호출에는 이러한 문자가 없습니다.ffmpeg로 시작하고 구분자 뒤에 두 번째 명령이 포함된 sh -c 프로세스 — 애플리케이션 로깅에 의존하지 않는 프로세스 트리 신호(auditd, eBPF, Falco, EDR)입니다.ffmpeg와 ffprobe는 정상이지만, 셸, 인터프리터 또는 네트워크 클라이언트는 비정상입니다.Running FFmpeg command: ffmpeg <command>로 기록하므로, 로그를 수집한다면 주입된 값을 찾는 가장 저렴한 방법입니다.options, format, codec, 또는 에 셸 메타문자가 포함된 MCP 도구 호출 로그.MITRE ATT&CK T1059.004 명령 및 스크립팅 인터프리터: Unix 셸.
패치된 릴리스가 없으므로 선택지는 격리(containment)와 제거입니다:
runFFmpegCommand에 도달하기 전에 거부하도록 만드세요.업스트림 수정 방향은 shell: true를 제거하고 ffmpeg에 인자 벡터를 전달하는 것입니다 — spawn("ffmpeg", ["-i", inputPath, …]) — 이 배열을 자유 형식 문자열이 아닌 허용 목록(allowlist)의 format, codec, pixelFormat 값으로 구성하는 방식입니다. Zod 유형 검증뿐만 아니라 콘텐츠 검증이 근본적인 요구사항입니다.
NIST SP 800-53r5 SI-10; OWASP ASVS v4 §5.3.8; CWE-78 완화 조치 M1 및 M2.
aws-mcp-server)동일한 연구 과정에서 나온 동반 권고문: CVE-2026-52616, CVE-2026-52618.
MIT — LICENSE 참조.
| CVE | CVE-2026-52617 |
| CWE | CWE-78 (OS 명령에 사용되는 특수 요소의 부적절한 중화) |
| 패키지 | @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 = 7.8 높음(High) (stdio 전송). 서버가 네트워크 전송으로 감싸여 있는 경우 AV:N → 9.8 심각(Critical). |
| 신고자 | s1ko (github.com/s1ko, [email protected]) |
| CVE 할당 | 2026-07-13, MITRE CNA-LR |
extract_audio | format |
create_video_from_images | codec, pixelFormat, extraOptions |
pixelFormatextraOptions| 날짜 | 이벤트 |
|---|
| 2026-05-29 | 게시된 tarball의 소스 검토를 통해 취약점 식별 |
| 2026-06-01 | 격리된 컨테이너에서 MCP stdio를 통해 동적으로 검증 |
| 2026-06-13 | 두 번째 호스트에서 재검증; 저장소에 Private Vulnerability Reporting이 활성화되어 있지 않고, package.json의 repository/bugs/homepage 필드가 github.com/yourusername 템플릿으로 남아 있어 문서화된 보안 연락처가 없음 |
| 2026-07-13 | MITRE CNA-LR이 CVE-2026-52617 배정, s1ko가 발견자로 기록 |
| 2026-08-22 | 기본 브랜치에서 싱크(sink) 재확인; npm 최신 버전이 여전히 0.2.1; 본 문서 게시 |