The Docker AuthZ Bypass Is Back: CVE-2026-34040

If you run an authorization plugin in front of the Docker daemon to decide who can do what, there is a good chance you assumed the plugin sees every request in full before it says yes or no. CVE-2026-34040 breaks that assumption. A specially crafted API request reaches the plugin stripped of its body, so the plugin approves a call it would otherwise deny.
The uncomfortable part is that this is not new. It is an incomplete fix of CVE-2024-41110, the maximum-severity AuthZ bypass patched back in July 2024. The same empty-body trick that was supposed to be closed is exploitable again in Docker Engine (Moby) before version 29.3.1.
TLDR
- What: CVE-2026-34040, an authorization plugin (AuthZ) bypass in Docker Engine / Moby, CVSS 8.8. Classified as CWE-288, authentication bypass through an alternate channel.
- How: A crafted request is forwarded to the AuthZ plugin without its body. The plugin evaluates an incomplete request and allows what it should block.
- Why it matters: It re-opens CVE-2024-41110. If an AuthZ plugin is your access-control boundary for the daemon, that boundary has a hole.
- Fix: Upgrade to Docker Engine / Moby 29.3.1 or later. Then stop treating an AuthZ plugin as your only guardrail.
Prerequisites
- A host running Docker Engine (Moby) where you can check the version and upgrade.
- You use, or are considering, an authorization plugin (OPA-based, Casbin-based, Twistlock/Prisma, or a homegrown one) to gate access to the daemon.
- Basic familiarity with how the Docker daemon exposes its API over a socket.
How the bypass works
Docker authorization plugins sit between the daemon and every API call. When a request comes in, the daemon forwards it to the plugin, the plugin returns allow or deny, and only then does the daemon act. Plugins routinely make decisions based on the request body, for example blocking POST /containers/create when the body asks for Privileged: true or a host path bind mount.
The bug is that under specific conditions the daemon forwards the request to the plugin without the body. The plugin sees the method and the path but not the payload it needs to judge. A rule like "deny privileged containers" never fires, because from the plugin's point of view there is no Privileged field to object to. The daemon then executes the full request, body and all.
attacker dockerd AuthZ plugin
| POST /containers/create | |
| {Privileged: true} | |
|------------------------->| forward (no body) |
| |--------------------->|
| | allow (nothing |
| |<---------------------| to deny)
| | |
| 201 Created (privileged container runs) |
|<-------------------------| |
This is the same class of flaw as CVE-2024-41110, which scored a perfect 10.0 and was patched in Docker Engine 23.0.14 and 27.1.0 in July 2024. The 2024 fix did not fully close the path, so the bypass is reachable again. CVE-2026-34040 is fixed in Moby 29.3.1.
This is an exploit against your access-control layer, not a remote code execution in the daemon itself. The risk is that a caller who is supposed to be restricted, for example a CI job or a tenant limited by policy, can escalate to actions the plugin was meant to forbid. Anyone who can reach the daemon API is in scope.
Are you affected?
You are exposed if both of these are true:
- Your Docker Engine / Moby version is older than 29.3.1.
- You rely on an authorization plugin to enforce what callers may do.
Check the running version:
If Server.Version is below 29.3.1 and Plugins.Authorization is not empty, patch.
If you do not run an AuthZ plugin at all, this specific CVE does not apply to you, but read the last section anyway, because it explains why an AuthZ plugin alone was never enough.
Fix it
The direct fix is the upgrade. Do the daemon, not just the client.
# Debian/Ubuntu, using Docker's apt repo
sudo apt-get update
sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io
# confirm the server is now 29.3.1 or later
docker version --format '{{.Server.Version}}'
# restarting the daemon is disruptive to running containers on that host;
# drain the node first if it is part of a Swarm or an orchestrated pool
sudo systemctl restart docker
On managed platforms you usually do not control the engine version directly. For a Swarm or a self-managed fleet, roll the upgrade node by node behind a drain. On a hosted container service, check the provider's engine version and security bulletins, since they patch on their own schedule.
Defense in depth: stop leaning on the plugin alone
The real lesson of a bug that comes back is that a single authorization plugin is a fragile boundary. Harden the layers around it.
- Lock down the socket. The Docker daemon socket is root-equivalent. Do not mount
/var/run/docker.sockinto containers, and do not expose the API over TCP without mutual TLS. Most AuthZ-bypass paths stop mattering if untrusted callers cannot reach the API in the first place. - Least privilege at the edges. Give CI runners and tenants the narrowest access they need. Prefer rootless Docker or a brokered build service over handing out daemon access and hoping the plugin holds.
- Do not pass privileged flags by default. Policy at the plugin is a backstop, not the primary control. Bake safe defaults into the platform, for example templates that never set
--privilegedor bind-mount the host root. - Watch for the tell. Log AuthZ plugin decisions. A spike in allowed
createcalls with unusually small request sizes, or allows where you would expect denies, is worth an alert.
Treat the AuthZ plugin as one control in a chain, socket access, network policy, least privilege, safe defaults, and audit logging. When any single link fails, as this CVE shows it can, the others should still hold.
Summary
CVE-2026-34040 is a reminder that "patched" is not the same as "closed." An incomplete fix of the 2024 Docker AuthZ bypass means a crafted request can once again reach your authorization plugin without its body and get waved through. Upgrade Docker Engine / Moby to 29.3.1, confirm the server version rather than the client, and use the outage as a prompt to make sure the plugin was never the only thing standing between an untrusted caller and a privileged container.
We earn commissions when you shop through the links below.
DigitalOcean
Cloud infrastructure for developers
Simple, reliable cloud computing designed for developers
DevDojo
Developer community & tools
Join a community of developers sharing knowledge and tools
SMTPfast
Developer-first email API
Send transactional and marketing email through a clean REST API. Detailed logs, webhooks, and embeddable signup forms in one dashboard.
QuizAPI
Developer-first quiz platform
Build, generate, and embed quizzes with a powerful REST API. AI-powered question generation and live multiplayer.
Want to support DevOps Daily and reach thousands of developers?
Become a SponsorFound an issue?
Related Posts
Also worth your time on this topic
5 Advanced Docker Features Worth Knowing
Go beyond Docker basics with BuildKit, multi-stage builds, health checks, init processes, and build secrets. Learn practical techniques that improve security, performance, and reliability.
Docker Security Hardening Checklist
Comprehensive security checklist for hardening Docker containers, images, and runtime environments.
60-90 minutes
Docker Multi-Stage Build Optimization
Learn to create efficient Docker images using multi-stage builds to reduce image size and improve security.
60 minutes