ffmpegsecurityvideo-processing

FFmpeg CVE October 2026: no patch exists. Contain them instead.

··10 min read
FFmpeg CVE October 2026: no patch exists. Contain them instead.

Your scanner went red on CVE-2026-107676 and CVE-2026-107678 this week, you went to bump the version, and there isn't one. Both are reported against FFmpeg through 9.0.2, the newest stable release on the 9.x line, and the Ubuntu security tracker lists no fixed package for supported LTS releases. The advice for the rest of the October batch, lock down the protocols, doesn't apply to these two.

Quick answer: In the FFmpeg CVE October 2026 batch, CVE-2026-107676 (uninitialized memory written into HDR10+/T.35 side data) and CVE-2026-107678 (stack exhaustion from recursive frees of MP4 pssh boxes) both fire on the uploaded file itself, so -protocol_whitelist does not cover them, and as of October 18, 2026 there is no patched FFmpeg release. Today's mitigations: bound the demuxer with -max_alloc and tight probe limits, strip T.35/SEI side data, reject files with thousands of pssh boxes before transcode, and run the binary unprivileged in a throwaway container with a wall-clock timeout. If you'd rather not patch a binary you maintain, send the job to a managed FFmpeg API like FFmpeg Micro instead, and the encoder stops being yours to patch.

Why blocking remote protocols doesn't cover these two

Most of the October 8 FFmpeg disclosures live in the code that opens a remote URL. CVE-2026-107698 is SSRF in ff_rtsp_connect(), which follows RTSP 3xx redirects without validating the Location header. CVE-2026-107675 is a missing host-key check in the libssh SFTP handler. For those, -protocol_whitelist file genuinely narrows the surface.

CVE-2026-107676 and CVE-2026-107678 fire when FFmpeg parses the bytes of a local file you already accepted. A protocol allowlist is irrelevant because no protocol other than file is involved.

That flag isn't a boundary anyway. CVE-2026-107697, from the same batch, lets a crafted HLS master playlist bypass -protocol_whitelist and allowed_extensions inside parse_playlist(). The PandaStack writeup on sandboxing untrusted uploads puts it well: argument allowlisting is a hardening layer, not a boundary, because the vulnerable parser runs after argument parsing.

CVE-2026-107676 writes your process memory into the video you publish

CVE-2026-107676 is scored low and filed as information disclosure, which makes it easy to skim past. For anyone who publishes the output, it's the more serious of the two. In av_dynamic_hdr_plus_to_t35(), up to three payload bytes are left uninitialized when tone_mapping_flag is 0. Crafted Matroska T.35 BlockAdditional data, or HEVC/AV1 SEI metadata, is enough to reach the serializer during an ordinary remux or transcode.

Those bytes come from your process heap, and the serializer runs on write, so they land in the output file you hand to a client, push to a CDN, or upload to TikTok. The serializer runs again everywhere the metadata appears, so a file engineered to carry it repeatedly turns one transcode into a slow read of memory that was holding your API tokens and other customers' frames a moment earlier.

Trackers disagree on severity: some records put it at 4.8, VulDB catalogs it at 3.3 as an uninitialized-pointer issue in the Matroska handler. Neither number describes "bytes of my worker's memory are now in a published video."

CVE-2026-107678 kills the worker, not just the job

CVE-2026-107678 is a stack exhaustion bug, published October 13 from an October 8 upstream report, rated Medium at CVSS 4.7 to 5.7 and classified CWE-674, Uncontrolled Recursion. The MOV demuxer builds an AVEncryptionInitInfo list in mov_read_pssh(), and av_encryption_init_info_free() in libavutil/encryption_info.c frees that list recursively. An MP4 carrying tens of thousands of tiny pssh boxes exhausts the stack on the way down, with quadratic CPU burn while it does.

The failure mode matters more than the score. A crash inside the demuxer doesn't return a failed job you can retry. It takes down the process, and in a self-hosted n8n container running FFmpeg through an Execute Command node, the process and the container are the same thing. One upload, and the automation watermarking tonight's clips is gone until something restarts it. Same shape as the n8n October CVE upgrade path: the video step breaks first.

One useful asymmetry: ffprobe triggers the pssh crash, because the bug is in the demuxer, but not the 107676 leak, because that bug is in the serializer and probing never writes T.35 output. Probe-on-upload isn't safe here, just differently exposed.

There is no tagged release, only two commits

FFmpeg 9.0.2 "Lei" shipped on September 18, 2026 and 8.1.3 "Hoare" on September 21, and per ffmpeg.org/download.html those are still the newest releases on their branches. There is no 9.1 and no 9.0.3. At least one CVE aggregator lists CVE-2026-107676 as "fixed in FFmpeg 9.1," a version that doesn't exist.

What does exist upstream is patch work in git: avutil: fix uninitialized memory read in HDR dynamic metadata (#24590) and avutil/encryption_info: avoid stack exhaustion freeing init info list (#24593). Cherry-picking those into your own build is legitimate if you already compile FFmpeg. It's also a commitment: you own a fork, and you own rebuilding every image that ships the binary: your n8n image, your worker image, and whatever CI uses for test fixtures. The same bind came up with CVE-2026-96611, where "is your build patched" had a different answer per image.

The mitigations you can actually apply today

Nothing below fixes either bug. Each one shrinks what an attacker gets. Penligent's defender writeup on the batch agrees: when patching isn't feasible, restrict untrusted media, isolate transcoding workloads, enforce memory limits, and cut risky configurations.

Bound the demuxer and pin the format

-max_alloc caps a single allocation from FFmpeg's malloc family and aborts with an error code instead of letting the OS OOM-killer decide. It's a global option, so it must come before -i, and it's silently useless anywhere else on the line.

ffmpeg -max_alloc 268435456 \
  -probesize 5000000 -analyzeduration 5000000 \
  -max_streams 8 -xerror \
  -f mp4 -i /in/upload.mp4 \
  -c:v libx264 -crf 23 -c:a aac /out/safe.mp4

Pinning -f mp4 stops the probe from wandering into demuxers you never meant to expose. -max_alloc is a heap control and CVE-2026-107678 exhausts the stack, so this command does not stop the pssh crash. Set it anyway, but it isn't your defense for that bug.

Strip the side data that reaches the serializer

For CVE-2026-107676, no T.35 or SEI metadata from the input should survive into the encode. The filter_units bitstream filter drops NAL and OBU types before the encoder sees them: HEVC prefix and suffix SEI are NAL types 39 and 40, H.264 SEI is type 6, and AV1 metadata OBUs are type 5.

# HEVC input: drop prefix and suffix SEI
ffmpeg -max_alloc 268435456 -i /in/upload.mkv \
  -c:v copy -bsf:v 'filter_units=remove_types=39|40' \
  -c:a copy /out/stripped.mkv

# AV1 input: drop metadata OBUs
ffmpeg -i /in/upload.mkv -c:v copy \
  -bsf:v 'filter_units=remove_types=5' -c:a copy /out/stripped.mkv

-map_metadata -1 does not help here. It clears container tags, not frame side data, and the HDR10+ payload rides on the frame.

For the pssh bug no flag skips mov_read_pssh(), so the only control is at the gate: count pssh occurrences in the file before FFmpeg opens it and reject anything with an implausible number. Real DRM-protected MP4s carry a handful, one per key system. Tens of thousands is a weapon, and a byte scan over the first few megabytes with a threshold of 16 costs microseconds. It's a heuristic, not a parser: you're filtering a crafted shape, not validating MP4.

Contain the process so a crash stays a crash

Containment limits blast radius: both bugs are in the parser, and the parser runs no matter how careful your argument list is. Run the binary as a throwaway, unprivileged container per upload:

docker run --rm --network none --read-only \
  --user 65534:65534 --cap-drop ALL \
  --security-opt no-new-privileges \
  --memory 512m --memory-swap 512m --pids-limit 64 \
  --tmpfs /tmp:size=64m \
  -v "$PWD/in:/in:ro" -v "$PWD/out:/out" \
  my-ffmpeg:9.0.2 timeout 120 ffmpeg -max_alloc 268435456 ...

Set the stack with ulimit -s 8192 inside the image so the recursion hits a guard page sooner and burns less CPU. The process still dies. --memory won't catch a stack overflow either, since the kernel delivers SIGSEGV rather than an OOM kill. The wall-clock timeout saves you from the quadratic CPU burn, and the per-upload container makes a dead FFmpeg just a dead FFmpeg instead of a dead automation host.

Common pitfalls

The mitigations above get applied wrong in a few specific ways.

  • Putting -max_alloc after -i. It's a global option and must precede the input, or it does nothing for the demuxer you meant to bound.
  • Treating -max_alloc as coverage for both CVEs. It's a heap cap, and CVE-2026-107678 is stack exhaustion.
  • Pinning to 8.1.3 and assuming you're clear. The HLS and TLS issues from this batch are fixed there, but the pssh and HDR10+ bugs are both reported "through 9.0.2," and an older branch is not an exemption.
  • Leaving ffprobe out of your threat model because it "only reads." The pssh crash is in the demuxer, so probing is a trigger.
  • Shipping the patched binary to one image. Your worker, your n8n container, your Lambda layer, and your CI fixture box each have their own copy.
  • Keeping -protocol_whitelist file as the only control. CVE-2026-107697 bypasses that flag through a crafted HLS playlist, and neither file-path bug needed a protocol in the first place.

Self-hosted versus managed, for this specific week

The honest comparison isn't features. It's who does the work when the scanner goes red and the release doesn't exist.

The jobSelf-hosted FFmpegManaged FFmpeg API
Patch with no tagged releaseCherry-pick #24590 and #24593, rebuild, retestNot your binary
Rebuild every image shipping ffmpegWorker, n8n, CI, Lambda layerNone
Isolate untrusted uploadsPer-upload container, timeouts, limits you operateRuns outside your network
Crash blast radiusYour worker or n8n containerA failed job, never billed
Cost of the firefightAn afternoon, every batchZero

The alternative to patching a binary on a Wednesday when there's no patch is not running the binary. FFmpeg Micro takes the upload, runs the encode on our infrastructure, and hands back a download URL, so an engineered MP4 reaches a parser that isn't inside your network and a crash is a failed job rather than a dead container. Failed jobs are never billed. If you've already priced your own GPU box, rerun the per-video arithmetic on RunPod with the patch treadmill as a line item.

FAQ

Is there an FFmpeg 9.1 or 9.0.3 I can upgrade to?

There is no FFmpeg 9.1 or 9.0.3 as of October 18, 2026. FFmpeg 9.0.2, released September 18, 2026, is still the newest 9.x on ffmpeg.org, and 8.1.3 from September 21 is the newest 8.1.x.

I'm pinned to an 8.x Docker image. Am I affected?

An 8.x pin does not exempt you from either bug. Both CVE-2026-107676 and CVE-2026-107678 are reported against FFmpeg through 9.0.2, which covers the 8.x line, and no distro has shipped a fixed package. Static builds and pinned images are in the worst position here, because no package manager will ever hand you the fix.

What should I do if my pipeline accepts arbitrary user uploads today?

For a pipeline that accepts arbitrary uploads, gate on a pssh count and a magic-byte check, pin the demuxer with -f, strip SEI and metadata units with filter_units, and run every job in an unprivileged throwaway container with a wall-clock timeout. Then decide whether you want to keep doing that for the next batch of CVEs.

If the answer is no, the quickstart runs presigned upload, transcode, poll, and download against a temporary key. The free tier is 200 tokens at sign-up, about 33 minutes of video, metered per second with no card required, enough to move one exposed job off your own binary tonight.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free