The FFmpeg Brotli CVE has no patch. Block it at ingest instead.

A crafted JPEG XL file can corrupt memory inside your FFmpeg worker, and there is no FFmpeg release that fixes it. The bug isn't in FFmpeg's code at all, which is exactly why apt upgrade ffmpeg does nothing and why your scanner still shows red. If you run FFmpeg or ffprobe over files other people upload, check whether your build reaches the vulnerable code, then close the door at ingest.
Quick answer: Yes, a JPEG XL upload can break an FFmpeg pipeline. CVE-2026-111497 is a CVSS 9.2 out-of-bounds write in Google's Brotli decoder (versions 1.0.3 through 1.2.0), and FFmpeg reaches it through libjxl when it decodes the Brotli-compressedbrobmetadata boxes in a.jxlfile. JFrog got instruction-pointer control from a crafted image. No FFmpeg release ships a fix because FFmpeg contains no Brotli code: if your ffmpeg dynamically links the systemlibbrotlidec, patch the distro brotli package and restart your workers; if it statically links or vendors libjxl v0.12.0, you are exposed until libjxl cuts a release, so refuse.jxlat the ingest boundary and pin-fplus-format_whitelistso FFmpeg stops picking a demuxer out of attacker bytes.
The bug is in Brotli, and FFmpeg is three layers downstream
CVE-2026-111497 is an out-of-bounds write (CWE-787) in Google's Brotli decoder, rated CVSS 9.2 by JFrog's security research team, who published the FFmpeg-specific path this week. Tenable's FAQ pins the root cause to error handling in block-switch processing: an invalid block switch gets treated as "needs more input" rather than an error, so decoding continues with invalid internal state. Affected ranges are 1.0.3 before 1.0.10, 1.1.0 before 1.1.1, and 1.2.0 before 1.2.1. The fixed releases landed October 21, 2026. The patch itself had existed in Brotli's source tree since February 27, with no release carrying it for nearly eight months.
Most coverage framed this as an HTTP problem, because the first disclosure came through Node.js accepting Content-Encoding: br on a request. FFmpeg's exposure arrives as a file instead, which matters more to anyone running a media pipeline.
A JPEG XL container stores compressed metadata in brob boxes. FFmpeg's libjxl-based JPEG XL decoder reads Exif metadata and asks libjxl to decompress those boxes, libjxl hands the bytes to BrotliDecoderDecompressStream(), and a crafted image corrupts decoder state. The crash surfaces later, during decoder cleanup, when a pointer derived from the attacker's payload gets freed. JFrog reproduced control of the instruction pointer in FFmpeg this way, though they did not demonstrate full code execution.
Any job that accepts user-supplied images is now a remote attack surface: images-to-video, product slideshows, thumbnail overlays, logo watermarks from a customer upload.
Check whether your ffmpeg is actually affected
Three commands tell you whether your build is exposed. Start with whether your binary has the decoder at all, because plenty of builds don't.
# 1. Does this build have the libjxl decoder compiled in?
ffmpeg -hide_banner -decoders | grep -i jxl
# 2. If yes: does it reach Brotli through a shared library?
ldd $(which ffmpeg) | grep -Ei 'brotli|jxl'
# 3. What version is that shared libbrotlidec?
dpkg -S $(ldd $(which ffmpeg) | awk '/brotlidec/ {print $3}')
dpkg -l libbrotli1 | tail -n1
If step 1 prints nothing, your build was configured without --enable-libjxl and this path doesn't exist in your binary. You still have the October MP4 and MKV CVEs, but not this one. Also check ffmpeg -hide_banner -buildconf | grep -o -- '--enable-libjxl' to confirm, since a decoder list can be filtered by other build flags.
If step 1 prints a jpegxl entry and step 2 shows libbrotlidec.so.1 and libjxl.so, you are dynamically linked and your fix is a package update plus a restart. Ubuntu has patched the brotli source package in 1.2.0-4ubuntu0.1 (26.10), 1.2.0-3ubuntu0.1 (26.04 LTS), 1.1.0-2ubuntu0.1 (24.04 LTS) and 1.0.9-2ubuntu0.1 (22.04 LTS), per Ubuntu's CVE tracker. Debian has bookworm in 1.0.9-2+deb12u1 and trixie in 1.1.0-2+deb13u1.
If step 2 prints nothing for brotli, you have a static build, and this is the bad case. Static builds (the johnvansickle tarballs, most ffmpeg-static npm installs, many self-built Docker images) carry their own copies of libjxl and Brotli. Updating the distro package does not touch them. Semgrep's writeup puts it plainly: bumping a top-level Brotli dependency never patches a vendored or submoduled copy, and code search misses those copies entirely.
The restart step people skip
Updating libbrotli1 while your worker is running leaves the running process holding the old mapped library. A long-lived FFmpeg worker, an n8n container, a queue consumer that forks ffmpeg from a resident parent: all still vulnerable until the process restarts. apt upgrade plus systemctl restart on the service, or a container recreate, not just a docker compose pull. We wrote about why a pull alone doesn't apply a security update when the n8n Node.js CVEs landed, and the mechanism is identical here.
Why there's no fixed FFmpeg version to pull
FFmpeg ships no Brotli code, so there is nothing for FFmpeg to patch and no FFmpeg release number that means "safe." The fix has to arrive through libjxl, and libjxl's current release, v0.12.0, predates it. The Broccoli2Shell tracker records libjxl bumping to Brotli 1.2.1 in PR #5062 on October 24, 2026, on main, with no release cut. Anyone whose build vendors libjxl v0.12.0 has no upstream artifact to upgrade to right now.
Contain it at ingest, not in the decoder
The reliable mitigation is to never let a .jxl reach the decoder, because you can't patch what you don't control. Three changes, in the order they pay off.
- Reject JPEG XL at the upload boundary by magic bytes, not by filename. A
.jxlrenamed to.pngstill decodes, because FFmpeg picks its demuxer by probing content. Check the first bytes before the file ever gets queued: the bare JXL codestream starts withFF 0A, and the ISOBMFF-wrapped form starts with00 00 00 0C 4A 58 4C 20 0D 0A 87 0A. Reject on either. - Tell FFmpeg what the input is instead of letting it guess. Pass an explicit
-ffor the format you expect, plus-format_whitelistand-protocol_whitelist fileso a surprise container can't select a surprise demuxer. The FFmpeg formats documentation covers both options. - Run the decode somewhere that holds nothing worth stealing. No API keys, no cloud metadata access, no mounted credentials, no write access to your output bucket. Instruction-pointer control in a process with your S3 keys in its environment is a very different incident from the same bug in a scratch container.
The second item looks like this for a job that should only ever receive an MP4:
# Permissive: FFmpeg probes the bytes and picks whatever demuxer matches
ffmpeg -i upload.bin -vf scale=1080:-2 out.mp4
# Pinned: wrong container fails at open instead of reaching an image decoder
ffmpeg -nostdin \
-protocol_whitelist file \
-format_whitelist mov,mp4,m4a \
-f mp4 -i upload.bin \
-vf scale=1080:-2 out.mp4
One honest limit on -format_whitelist: it constrains demuxer selection, not every decoder reachable afterward. Whitelisting image2 for PNG thumbnails still leaves an image decode open, which is why the magic-byte check at ingest matters too.
Treat ffprobe as equally dangerous. It runs the same demuxers and the same metadata parsing, including the Exif path into libjxl, so probing an untrusted file is the same exposure with less output.
Self-hosted versus managed, on this specific CVE
The split between self-hosted FFmpeg and a managed API isn't about which side has vulnerabilities. It's who owns the rebuild when the fix exists nowhere you can apt install it.
| Self-hosted FFmpeg | FFmpeg Micro | |
|---|---|---|
| Patch path for this CVE | Distro brotli update plus worker restart, or a full rebuild if static | Handled on our side |
| If your build vendors libjxl v0.12.0 | No upstream release to pull; rebuild against Brotli 1.2.1 yourself | Not your problem |
| Ingest allowlist | You write the magic-byte check and the `-f` pinning | Input formats are validated before a job runs |
| Credentials near the decoder | Whatever your worker's environment holds | Your keys never sit in the decode process |
| Second CVE this month | Second forced rebuild this month | Zero |
The offer here is to stop owning a binary that parses attacker-supplied bytes. FFmpeg Micro runs the FFmpeg layer for over 700 developers and automation builders, patches it on our own schedule, and gives you a transcode as one API call with no encoder to maintain. You submit a job, poll for status, download the output. We take the 2 a.m. CVE email.
This is the second file-path CVE in a month where upgrading isn't the answer
Three weeks ago the same pattern ran with crafted MP4 and MKV files: CVE-2026-107676 writing uninitialized process memory into your output file, and CVE-2026-107678 exhausting the stack with tens of thousands of tiny pssh boxes. Both affect FFmpeg through 9.0.2, the current stable line, and both were fixed in master with no 9.0.x release carrying the fixes. We published the containment pattern then: FFmpeg CVE October 2026: no patch exists. Contain them instead.
The shape repeats. A file-triggered bug, reachable from an ordinary upload, with the fix sitting in a git branch while scanners flag your pinned image. Add the Node.js Brotli releases on October 21 that forced a rebuild of every custom n8n + ffmpeg Docker image, and the version floor rising underneath you (OBS Studio 33.0 dropped FFmpeg 6.x and 7.x support on October 23), and the maintenance bill for self-hosting a media decoder is a recurring line item, not a one-time setup cost. We also covered what to re-test before upgrading to FFmpeg 9.1.
FAQ
Is my ffmpeg affected by CVE-2026-111497 if it doesn't have libjxl?
An ffmpeg build without the libjxl decoder does not have this attack path. Run ffmpeg -hide_banner -decoders | grep -i jxl; if nothing prints and ffmpeg -buildconf shows no --enable-libjxl, a crafted JPEG XL file has no route to BrotliDecoderDecompressStream() in your binary. Other Brotli consumers on the same host (your Node.js runtime, your HTTP client) are a separate check.
Does apt upgrade fix the FFmpeg Brotli CVE?
Updating the distro brotli package fixes CVE-2026-111497 for an ffmpeg that dynamically links libbrotlidec, but only after every process using it restarts. Run ldd $(which ffmpeg) | grep brotli first: if that prints a path, patch and restart. If it prints nothing, you have a static build with its own vendored Brotli copy, and the package update changes nothing for you.
Can FFmpeg still decode a .jxl file I renamed to .png?
FFmpeg selects its demuxer by probing file content, not by file extension, so renaming a JPEG XL file to .png or .mp4 does not prevent it from being decoded as JPEG XL. Extension-based upload filters are not a mitigation for this CVE. Check magic bytes at ingest and pass an explicit -f to FFmpeg.
Is this a crash or real code execution?
JFrog reproduced instruction-pointer control in FFmpeg from a crafted JPEG XL file but did not demonstrate working code execution. Treat it as an out-of-bounds write with a credible path to execution, not a denial-of-service bug, so isolating the decode process from credentials matters as much as blocking the format.
Is ffprobe safer than ffmpeg on untrusted input?
Running ffprobe on an untrusted file carries the same risk as running ffmpeg on it. ffprobe uses the same demuxers and the same metadata parsing code, including the Exif path that hands brob box contents to libjxl, so using it as a pre-flight validation step does not reduce your exposure.
If you'd rather not hand-carry a Brotli rebuild into a vendored libjxl this week, the quickstart gets you a working API key and a finished transcode on the free tier without a card.
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.
You might also like

FFmpeg CVE October 2026: no patch exists. Contain them instead.
FFmpeg CVE October 2026: CVE-2026-107676 and CVE-2026-107678 fire on the uploaded file, and no patched release exists. The mitigations that work today.

Don't send raw video input to an AI model. Prep it in FFmpeg.
Raw video input to an AI model burns the token budget. Four FFmpeg prep steps (downscale, trim, split audio, keyframes) cut muse-wonder-1.0 input costs.

FFmpeg concat audio gap isn't your cut. It's AAC priming.
The silence between joined clips is an FFmpeg concat audio gap caused by AAC priming samples, not your cut point. How to prove it and the fixes that work.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free