From 743a91e38a2e8e931bdad4dafa8a3ac3dd692f78 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 2 Nov 2026 12:20:56 -0800 Subject: [PATCH 1/3] fix(media): restrict ffmpeg inputs to media demuxers --- apps/sim/lib/audio/extractor.test.ts | 2 + apps/sim/lib/media/ffmpeg-process.ts | 56 +++++++++++++++++++++++++--- apps/sim/lib/media/ffmpeg.test.ts | 8 ++++ 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/apps/sim/lib/audio/extractor.test.ts b/apps/sim/lib/audio/extractor.test.ts index e399794e35a..67d1a784dcc 100644 --- a/apps/sim/lib/audio/extractor.test.ts +++ b/apps/sim/lib/audio/extractor.test.ts @@ -100,6 +100,8 @@ describe('audio FFmpeg execution', () => { '-nostdin', '-protocol_whitelist', 'file,pipe', + '-format_whitelist', + expect.any(String), '-i', expect.stringMatching(/input\.mp4$/), '-f', diff --git a/apps/sim/lib/media/ffmpeg-process.ts b/apps/sim/lib/media/ffmpeg-process.ts index 8bff63448f4..9668cd2680c 100644 --- a/apps/sim/lib/media/ffmpeg-process.ts +++ b/apps/sim/lib/media/ffmpeg-process.ts @@ -20,18 +20,64 @@ const FFMPEG_BASE_ARGS = ['-y', '-nostdin'] as const */ const INPUT_PROTOCOL_WHITELIST = ['-protocol_whitelist', 'file,pipe'] as const -/** FFmpeg argv: base flags, then `args` with the protocol whitelist before every input. */ +/** + * Demuxers an input may probe as: media containers that read only the bytes + * they are given. FFmpeg picks the demuxer from content, not the file name, and + * the bytes are user-supplied, so without this an upload can select a demuxer + * that opens further local paths (`concat`, `hls`, `dash`, `imf`) and the only + * barrier left is that demuxer's own upstream defaults. Any other input fails + * with "Format not on whitelist" before the demuxer opens anything. + */ +const MEDIA_DEMUXERS = [ + 'mov', + 'matroska', + 'avi', + 'flv', + 'asf', + 'mpegts', + 'mpeg', + 'mp3', + 'wav', + 'ogg', + 'flac', + 'aac', + 'aiff', + 'amr', + 'caf', + 'png_pipe', + 'jpeg_pipe', + 'webp_pipe', + 'gif', + 'image2', +].join(',') + +/** + * FFmpeg argv: base flags, then `args` with the protocol and format whitelists + * before every input. A demuxer the caller forces with `-f` (the concat list, + * the `lavfi` silence source) is added to that input's format whitelist, so + * the inputs it opens in turn are still held to media demuxers. + */ export function ffmpegArgs(args: readonly string[]): string[] { - return [ - ...FFMPEG_BASE_ARGS, - ...args.flatMap((arg) => (arg === '-i' ? [...INPUT_PROTOCOL_WHITELIST, arg] : [arg])), - ] + const argv: string[] = [...FFMPEG_BASE_ARGS] + let forcedDemuxer: string | undefined + for (const [index, arg] of args.entries()) { + if (arg === '-f') forcedDemuxer = args[index + 1] + if (arg === '-i') { + const formats = forcedDemuxer ? `${forcedDemuxer},${MEDIA_DEMUXERS}` : MEDIA_DEMUXERS + argv.push(...INPUT_PROTOCOL_WHITELIST, '-format_whitelist', formats) + forcedDemuxer = undefined + } + argv.push(arg) + } + return argv } /** FFprobe argv that prints the format and streams of `filePath` as JSON. */ export function ffprobeJsonArgs(filePath: string): string[] { return [ ...INPUT_PROTOCOL_WHITELIST, + '-format_whitelist', + MEDIA_DEMUXERS, '-v', 'error', '-print_format', diff --git a/apps/sim/lib/media/ffmpeg.test.ts b/apps/sim/lib/media/ffmpeg.test.ts index c14e96ecc7e..91b19710bdd 100644 --- a/apps/sim/lib/media/ffmpeg.test.ts +++ b/apps/sim/lib/media/ffmpeg.test.ts @@ -324,12 +324,16 @@ describe('runFfmpegOperation argument vectors', () => { '-nostdin', '-protocol_whitelist', 'file,pipe', + '-format_whitelist', + expect.any(String), '-i', expect.stringMatching(/in-0\.mp4$/), '-stream_loop', '-1', '-protocol_whitelist', 'file,pipe', + '-format_whitelist', + expect.any(String), '-i', expect.stringMatching(/in-1\.mp4$/), '-map', @@ -353,6 +357,8 @@ describe('runFfmpegOperation argument vectors', () => { '-nostdin', '-protocol_whitelist', 'file,pipe', + '-format_whitelist', + expect.any(String), '-i', expect.stringMatching(/in-0\.mp4$/), '-ss', @@ -373,6 +379,8 @@ describe('runFfmpegOperation argument vectors', () => { '3', '-protocol_whitelist', 'file,pipe', + '-format_whitelist', + expect.any(String), '-i', expect.stringMatching(/in-0\.mp4$/), '-frames:v', From 2889e3df82c599460dd499a451d00920432151c8 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 2 Nov 2026 12:29:32 -0800 Subject: [PATCH 2/3] fix(media): allow bmp, tiff, and ico image demuxers --- apps/sim/lib/media/ffmpeg-process.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/sim/lib/media/ffmpeg-process.ts b/apps/sim/lib/media/ffmpeg-process.ts index 9668cd2680c..7567a9e8ca9 100644 --- a/apps/sim/lib/media/ffmpeg-process.ts +++ b/apps/sim/lib/media/ffmpeg-process.ts @@ -47,6 +47,9 @@ const MEDIA_DEMUXERS = [ 'png_pipe', 'jpeg_pipe', 'webp_pipe', + 'bmp_pipe', + 'tiff_pipe', + 'ico', 'gif', 'image2', ].join(',') From fe45621604bfca77d385e5e189ceae53425e05fb Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 2 Nov 2026 12:38:41 -0800 Subject: [PATCH 3/3] fix(media): allow apng demuxer --- apps/sim/lib/media/ffmpeg-process.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sim/lib/media/ffmpeg-process.ts b/apps/sim/lib/media/ffmpeg-process.ts index 7567a9e8ca9..056f758f390 100644 --- a/apps/sim/lib/media/ffmpeg-process.ts +++ b/apps/sim/lib/media/ffmpeg-process.ts @@ -45,6 +45,7 @@ const MEDIA_DEMUXERS = [ 'amr', 'caf', 'png_pipe', + 'apng', 'jpeg_pipe', 'webp_pipe', 'bmp_pipe',