Skip to content

Commit 29dd567

Browse files
authored
fix(media): restrict ffmpeg inputs to media demuxers (#9577)
1 parent c19575a commit 29dd567

3 files changed

Lines changed: 65 additions & 5 deletions

File tree

‎apps/sim/lib/audio/extractor.test.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ describe('audio FFmpeg execution', () => {
100100
'-nostdin',
101101
'-protocol_whitelist',
102102
'file,pipe',
103+
'-format_whitelist',
104+
expect.any(String),
103105
'-i',
104106
expect.stringMatching(/input\.mp4$/),
105107
'-f',

‎apps/sim/lib/media/ffmpeg-process.ts‎

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,68 @@ const FFMPEG_BASE_ARGS = ['-y', '-nostdin'] as const
2020
*/
2121
const INPUT_PROTOCOL_WHITELIST = ['-protocol_whitelist', 'file,pipe'] as const
2222

23-
/** FFmpeg argv: base flags, then `args` with the protocol whitelist before every input. */
23+
/**
24+
* Demuxers an input may probe as: media containers that read only the bytes
25+
* they are given. FFmpeg picks the demuxer from content, not the file name, and
26+
* the bytes are user-supplied, so without this an upload can select a demuxer
27+
* that opens further local paths (`concat`, `hls`, `dash`, `imf`) and the only
28+
* barrier left is that demuxer's own upstream defaults. Any other input fails
29+
* with "Format not on whitelist" before the demuxer opens anything.
30+
*/
31+
const MEDIA_DEMUXERS = [
32+
'mov',
33+
'matroska',
34+
'avi',
35+
'flv',
36+
'asf',
37+
'mpegts',
38+
'mpeg',
39+
'mp3',
40+
'wav',
41+
'ogg',
42+
'flac',
43+
'aac',
44+
'aiff',
45+
'amr',
46+
'caf',
47+
'png_pipe',
48+
'apng',
49+
'jpeg_pipe',
50+
'webp_pipe',
51+
'bmp_pipe',
52+
'tiff_pipe',
53+
'ico',
54+
'gif',
55+
'image2',
56+
].join(',')
57+
58+
/**
59+
* FFmpeg argv: base flags, then `args` with the protocol and format whitelists
60+
* before every input. A demuxer the caller forces with `-f` (the concat list,
61+
* the `lavfi` silence source) is added to that input's format whitelist, so
62+
* the inputs it opens in turn are still held to media demuxers.
63+
*/
2464
export function ffmpegArgs(args: readonly string[]): string[] {
25-
return [
26-
...FFMPEG_BASE_ARGS,
27-
...args.flatMap((arg) => (arg === '-i' ? [...INPUT_PROTOCOL_WHITELIST, arg] : [arg])),
28-
]
65+
const argv: string[] = [...FFMPEG_BASE_ARGS]
66+
let forcedDemuxer: string | undefined
67+
for (const [index, arg] of args.entries()) {
68+
if (arg === '-f') forcedDemuxer = args[index + 1]
69+
if (arg === '-i') {
70+
const formats = forcedDemuxer ? `${forcedDemuxer},${MEDIA_DEMUXERS}` : MEDIA_DEMUXERS
71+
argv.push(...INPUT_PROTOCOL_WHITELIST, '-format_whitelist', formats)
72+
forcedDemuxer = undefined
73+
}
74+
argv.push(arg)
75+
}
76+
return argv
2977
}
3078

3179
/** FFprobe argv that prints the format and streams of `filePath` as JSON. */
3280
export function ffprobeJsonArgs(filePath: string): string[] {
3381
return [
3482
...INPUT_PROTOCOL_WHITELIST,
83+
'-format_whitelist',
84+
MEDIA_DEMUXERS,
3585
'-v',
3686
'error',
3787
'-print_format',

‎apps/sim/lib/media/ffmpeg.test.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,16 @@ describe('runFfmpegOperation argument vectors', () => {
324324
'-nostdin',
325325
'-protocol_whitelist',
326326
'file,pipe',
327+
'-format_whitelist',
328+
expect.any(String),
327329
'-i',
328330
expect.stringMatching(/in-0\.mp4$/),
329331
'-stream_loop',
330332
'-1',
331333
'-protocol_whitelist',
332334
'file,pipe',
335+
'-format_whitelist',
336+
expect.any(String),
333337
'-i',
334338
expect.stringMatching(/in-1\.mp4$/),
335339
'-map',
@@ -353,6 +357,8 @@ describe('runFfmpegOperation argument vectors', () => {
353357
'-nostdin',
354358
'-protocol_whitelist',
355359
'file,pipe',
360+
'-format_whitelist',
361+
expect.any(String),
356362
'-i',
357363
expect.stringMatching(/in-0\.mp4$/),
358364
'-ss',
@@ -373,6 +379,8 @@ describe('runFfmpegOperation argument vectors', () => {
373379
'3',
374380
'-protocol_whitelist',
375381
'file,pipe',
382+
'-format_whitelist',
383+
expect.any(String),
376384
'-i',
377385
expect.stringMatching(/in-0\.mp4$/),
378386
'-frames:v',

0 commit comments

Comments
 (0)