Your PHP Docker image has an FFmpeg layer. Who patches it?

A scanner flagged CVE-2026-107678 against your php:8.3-fpm container, you ran apt upgrade, rebuilt, rescanned, and the finding is still sitting there.
In a PHP Docker FFmpeg image, the team that wrote the Dockerfile patches it, and no one else does. RUN apt-get install -y ffmpeg makes your application container the owner of a media decoder that parses attacker-supplied files, on Debian's release cadence rather than FFmpeg's, and for the October 2026 file-path CVEs there is currently no patched package to install. Composer packages like PHP-FFMpeg and laravel-ffmpeg wrap that binary. They do not maintain it.
Which FFmpeg version apt actually hands your PHP image
The version you get is decided by a tag suffix most Dockerfiles don't spell out. The official PHP image publishes both 8.3-fpm-bookworm and 8.3-fpm-trixie (docker-library/docs), so a bare php:8.3-fpm resolves to whichever Debian suite is current when you build, and that suite picks your FFmpeg.
| Base tag | Debian suite | `apt install ffmpeg` gives | Upstream branch head |
|---|---|---|---|
| `php:8.3-fpm-bookworm` | Debian 12 | 7:5.1.9-0+deb12u1 | 5.1.10 |
| `php:8.3-fpm-trixie` | Debian 13 | 7:7.1.2-0+deb13u1 (later 7.1.4) | 7.1.5 |
| upstream maintained lines | not packaged | 8.1.3, 9.0.2 |
Debian's bookworm ffmpeg reached 5.1.9 on July 11, 2026 (Launchpad), and trixie carries the 7.1.x line (packages.debian.org), while endoflife.date tracks the maintained branches one or three patch releases further along. Worth checking your own build rather than trusting a tutorial:
docker run --rm php:8.3-fpm-bookworm sh -c \
'apt-get update -qq && apt-cache policy ffmpeg brotli'
Then compare against what laravel-ffmpeg claims to support. Its README says it's tested with FFmpeg 4.4 and 5.0. Your container is running something newer than the wrapper's test matrix and older than upstream's patched branch, at the same time.
The crafted .jxl upload is the case people miss
An FFmpeg CVE sounds like a video problem, which is why teams with an avatar-upload form assume it isn't theirs. CVE-2026-111497 is a CVSS 9.2 out-of-bounds write in Google's Brotli decoder, affecting 1.0.3 through 1.2.0 and fixed in 1.0.10, 1.1.1 and 1.2.1 (Debian security tracker). FFmpeg never calls Brotli directly. It gets there through libjxl: a JPEG XL file stores compressed metadata in brob boxes, libjxl passes those bytes to BrotliDecoderDecompressStream(), and JFrog's Brotli2Shell writeup reproduced control of the instruction pointer in FFmpeg from a crafted .jxl file.
Debian lists libjxl-dev among the build dependencies for its current stable ffmpeg source package, so the distro binary decodes JPEG XL. The upgrade you'd make to get a newer FFmpeg, bookworm to trixie, is also the upgrade that adds that decode path. We wrote up the ingest-side defense separately in the FFmpeg Brotli CVE has no patch, block it at ingest instead.
Two more from the same autumn fire on the ordinary file path. CVE-2026-107678 is a stack exhaustion in av_encryption_init_info_free(), triggered by an MP4 carrying tens of thousands of tiny pssh boxes, affecting FFmpeg through 9.0.2 (Ubuntu security). CVE-2026-107676 writes up to three bytes of uninitialized process memory into output files from crafted Matroska T.35 or HEVC/AV1 SEI metadata, which means the leak lands in a file your app then publishes. And PixelSmash, CVE-2026-8461, is a heap out-of-bounds write in the MagicYUV decoder at CVSS 8.8, reachable by uploading a crafted AVI, MKV or MOV to anything that decodes with libavcodec (JFrog).
Telling a package-fix CVE from a no-release CVE
Both kinds show up in the same scanner report with the same red badge, and only one of them responds to a rebuild. The Brotli bug is the good case: Debian shipped fixed brotli packages in both stable suites, 1.0.9-2+deb12u1 for bookworm and 1.1.0-2+deb13u1 for trixie, so on a Debian-based PHP image an apt-get update && apt-get upgrade in a fresh build genuinely closes it. A statically linked or vendored FFmpeg build gets none of that.
The October FFmpeg batch is the bad case. CVE-2026-107676 and CVE-2026-107678 are still listed as "Needs evaluation" with no fixed package across Ubuntu 26.04, 24.04, 22.04, 20.04, 18.04 and 16.04, and PixelSmash is fixed in FFmpeg 8.1.2, a version no Debian stable branch offers. The practical test is one lookup per finding: if the security tracker names a fixed package version in your suite, rebuild; if it names only an upstream release your distro doesn't carry, rebuilding is theater. The longer version of that argument is in FFmpeg CVE October 2026: no patch exists, contain them instead.
Pinning digests matters here too. A docker compose pull against an already-pinned tag won't fetch the fixed brotli, for the same reason it won't apply an n8n security update: no rebuild, no new packages.
Where "just pin the version" stops working
Pinning is the standard advice for a reproducible image, and for the PHP runtime it's right. For the FFmpeg layer it buys reproducibility and sells currency, because the floor underneath you keeps rising. OBS Studio 33.0.0, released October 23, 2026, removed support for building against FFmpeg 6.x and 7.x and dropped Ubuntu 24.04 LTS (release notes). Stable distros still ship 5.1 and 7.1. Every month, a pinned apt install ffmpeg sits further from the code upstream actually tests.
Jumping majors to catch up has its own bill, and it lands in your PHP source rather than your Dockerfile. Hardcoded command strings built in a Blade controller or a queued job break on flag changes, which is the whole subject of FFmpeg 9.1: what to re-test before you upgrade. A wrapper library doesn't shield you either; it generates those flags from its own assumptions about the binary's version.
Pinning and upgrading are both answers to a version question. The harder question is whether a decoder with this patch cadence belongs in a container that also holds your .env, your database credentials and your session store, running as the same www-data the FPM pool runs as. If a crafted upload gets code execution inside that container, "the FFmpeg layer" is not what it reached.
Containment that actually shrinks the blast radius
Keep the layer if you must, but make these changes rather than only the ones a Dockerfile tutorial shows.
- Move the binary out of the web container into the queue worker image. PHP-FPM shouldn't have a decoder on its PATH at all; a Laravel job that dispatches to a worker already gives you that seam.
- Run FFmpeg as a user that isn't the FPM user, with
--cap-drop ALL, a read-only root filesystem, a tmpfs scratch directory, and--network noneon the worker that only reads local files. - Set hard limits so a stack-exhaustion bug costs you one job: a wall-clock timeout, a memory cap, and a pids limit. Never let the ffmpeg process be the container's PID 1.
- Allowlist inputs at ingest by magic bytes, not by file extension or MIME header, and reject the formats your product never needs. If you accept images, decide explicitly about .jxl, .heic and .avif.
- Pass
-protocol_whitelist fileand never hand FFmpeg a user-supplied URL. A remote URL isn't safe is a separate bypass class from anything above. - Track three package lines in your scanner, not one:
ffmpeg,brotliandlibjxl. The CVE that bites you may be filed against none of them. - Rebuild on a schedule, not on a deploy. Pin by digest, refresh the pin weekly in CI, and the rebuild is what applies the fixed
brotli.
Or run the decoder somewhere that isn't your application container
Every item on that checklist is work you do to make a decoder less dangerous inside a container that holds your secrets. The other option is that the decoder isn't there. Send the file to an API, get a processed file back, and the parsing of attacker-supplied bytes happens somewhere your app's credentials aren't.
| FFmpeg layer in your PHP image | Decoder outside your app | |
|---|---|---|
| Patch owner | you, on Debian's cadence | the API operator |
| Version you run | 5.1.9 or 7.1.2 | current |
| What a crafted .jxl reaches | FPM user, `.env`, DB creds | nothing of yours |
| Response to a no-release CVE | carry patches or wait | not your rebuild |
That's where FFmpeg Micro fits for a PHP app: one API call, no binary in your image, and an official PHP SDK (ffmpeg-micro/ffmpeg-micro-php on Packagist, PHP 8.1+) whose submit-then-poll shape maps straight onto a Laravel queued job. The raw request is as plain as the Dockerfile line you're deleting:
curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputs": [{"url": "gs://your-bucket/1234567890-upload.mp4"}],
"outputFormat": "mp4",
"preset": {"quality": "medium", "resolution": "1080p"}
}'
You poll /v1/transcodes/:id until it reports completed, then call /download for a signed URL. The free tier is 200 tokens at sign-up, roughly 33 minutes of video, no card, and failed jobs are never billed. Related reading for this same stack: the ffmpeg-php extension is dead and shell_exec has been disabled, run FFmpeg jobs from PHP anyway.
FAQ
Does apt upgrade fix an FFmpeg CVE in my PHP container?
An apt-get upgrade in a fresh build fixes an FFmpeg-adjacent CVE only when your Debian suite has a fixed package for it. The Brotli bug qualifies, with 1.0.9-2+deb12u1 in bookworm and 1.1.0-2+deb13u1 in trixie. The October 2026 FFmpeg file-path CVEs do not: Ubuntu's tracker shows "Needs evaluation" and no fixed package on every supported LTS.
I only accept image uploads. Is the FFmpeg CVE stream still my problem?
Image-only upload forms are in scope, because FFmpeg decodes stills. A crafted JPEG XL file reaches the vulnerable Brotli decoder through libjxl, and JFrog reproduced instruction-pointer control that way, so any thumbnailing or preview step that calls libavcodec on user images is parsing attacker-controlled input.
Does laravel-ffmpeg or PHP-FFMpeg patch the FFmpeg binary?
Neither package ships or patches an FFmpeg binary. PHP-FFMpeg is explicit that you supply working ffmpeg and ffprobe executables, and laravel-ffmpeg only configures their paths through ffmpeg.binaries and ffprobe.binaries. The patch level of the thing doing the decoding is entirely your Dockerfile's business.
Should the FFmpeg binary live in the web container or the queue worker?
Put the FFmpeg binary in the queue worker image if you keep it at all, and leave PHP-FPM without a decoder on its PATH. A worker can run as a different user with dropped capabilities, no network and a read-only filesystem, none of which you can do to the container serving HTTP.
Can I just install FFmpeg 8.1.2 in a Debian-based PHP image?
Installing FFmpeg 8.1.2 in php:8.3-fpm means leaving apt behind: a third-party repository, a static build, or compiling in a multi-stage Dockerfile. All three move the patch job from Debian's security team to you, and a static build also loses the shared brotli fix that an ordinary package update would have delivered.
If your Dockerfile has that apt-get install -y ffmpeg line and nobody on the project has a rebuild trigger for it, the quickstart is the fastest way to see what the same job looks like without the layer: sign up and the dashboard creates a temporary API key, then runs presigned upload, transcode, poll and download in front of you. Sign up free means no servers to run and no FFmpeg to install, called from your PHP code, from n8n, Make and Zapier, or from your AI agents, with a free tier to test it on your own footage.
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

The ffmpeg-php extension is dead. What to use on PHP 8.4 instead
ffmpeg-php on PHP 8 is a dead end: the last release was 2009 and PECL is deprecated. Map ffmpeg_movie, getDuration and getFrame to what works on PHP 8.4.

shell_exec has been disabled. Run FFmpeg jobs from PHP anyway
shell_exec has been disabled for security reasons? Why removing one entry won't help, why PHP-FFMpeg fails, and how to encode video from PHP with no shell.

docker compose pull won't apply the n8n security update patch
The n8n security update patch landed Oct 14, 2026. If your Docker image has FFmpeg baked in, docker compose pull won't patch it. The rebuild, in order.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free