POSIX filenames can contain any byte except \0 and /, including \x1b (ESC). The error paths in main.cpp / videothumbnailer.cpp / the writers concatenate filenames straight into std::cerr output, and the project never installs an av_log_set_callback, so FFmpeg's own log output (which can include track titles and other container metadata) goes to stderr unfiltered. The PNG Thumb::URI tEXt chunk also gets the raw filename via pngwriter.cpp:setText.
A file named foo\x1b]8;;https://attacker/\x07click here\x1b]8;;\x07.mp4 triggers an error with that filename and the operator's terminal renders "click here" as a clickable hyperlink to the attacker's URL — works in gnome-terminal, iTerm2, kitty, modern xterm. OSC 52 (\x1b]52;c;BASE64\x07) writes to the system clipboard in some configurations. Title spoofing and screen clearing are also reachable. For the PNG metadata case, the raw bytes end up in published thumbnails.
I confirmed by running the unpatched binary that \x1b bytes survive end-to-end to stderr.
The patch adds StringOperations::sanitizeForOutput (escapes C0 except \t/\n, DEL, and C1 as \xNN, leaves printable Latin-1 alone so accented filenames stay readable) and applies it at:
- every exception-message construction that includes a filename (moviedecoder, jpegwriter, pngwriter, rgbwriter)
- every direct
std::cerr/std::cout site in main.cpp that emits optarg/filename/seekTime/e.what()
- the log callback in main.cpp
- the
TraceMessage sites in videothumbnailer.cpp that include e.what() (defense-in-depth)
PngWriter::setText for both key and value, so Thumb::URI and any future tEXt chunks are automatically safe
- an
av_log_set_callback installed in main() so FFmpeg's own messages are sanitized too
Verified by feeding printf '/tmp/foo_\033]0;X\007' as the input filename: zero raw ESC bytes in stderr, the bytes show up as literal \x1B text instead. PNG tEXt chunks also clean. Eleven unit tests included for the sanitizer (OSC 0/7/8/52, CSI, C1, DEL, NUL, UTF-8, tab/newline, empty).
Suggested patch:
02-output-sanitization.patch
POSIX filenames can contain any byte except
\0and/, including\x1b(ESC). The error paths in main.cpp / videothumbnailer.cpp / the writers concatenate filenames straight intostd::cerroutput, and the project never installs anav_log_set_callback, so FFmpeg's own log output (which can include track titles and other container metadata) goes to stderr unfiltered. The PNGThumb::URItEXtchunk also gets the raw filename viapngwriter.cpp:setText.A file named
foo\x1b]8;;https://attacker/\x07click here\x1b]8;;\x07.mp4triggers an error with that filename and the operator's terminal renders "click here" as a clickable hyperlink to the attacker's URL — works in gnome-terminal, iTerm2, kitty, modern xterm. OSC 52 (\x1b]52;c;BASE64\x07) writes to the system clipboard in some configurations. Title spoofing and screen clearing are also reachable. For the PNG metadata case, the raw bytes end up in published thumbnails.I confirmed by running the unpatched binary that
\x1bbytes survive end-to-end to stderr.The patch adds
StringOperations::sanitizeForOutput(escapes C0 except\t/\n, DEL, and C1 as\xNN, leaves printable Latin-1 alone so accented filenames stay readable) and applies it at:std::cerr/std::coutsite inmain.cppthat emitsoptarg/filename/seekTime/e.what()TraceMessagesites in videothumbnailer.cpp that includee.what()(defense-in-depth)PngWriter::setTextfor both key and value, soThumb::URIand any future tEXt chunks are automatically safeav_log_set_callbackinstalled inmain()so FFmpeg's own messages are sanitized tooVerified by feeding
printf '/tmp/foo_\033]0;X\007'as the input filename: zero raw ESC bytes in stderr, the bytes show up as literal\x1Btext instead. PNGtEXtchunks also clean. Eleven unit tests included for the sanitizer (OSC 0/7/8/52, CSI, C1, DEL, NUL, UTF-8, tab/newline, empty).Suggested patch:
02-output-sanitization.patch