Moby is the open-source project behind Docker, making it easy to create, manage, and run software containers. While containers usually keep things secure and isolated, sometimes bugs open the door to unexpected privilege escalations. CVE-2022-24769 is one such bug: in versions of Moby (Docker Engine) before 20.10.14, Linux containers could unintentionally start with an extra set of “inheritable” process capabilities. This rare scenario could allow unprivileged users *inside* a container to amplify their power by exploiting the Linux capability system.
In this article, we’ll break down what happened, show how it works with code snippets, and walk you through both the exploit and the fix. We’ll keep it all in plain English, and link to real sources so you can dig deeper.
What Are Linux Capabilities?
On Linux, capabilities allow the kernel to break up the all-powerful “root” access into distinct privileges (like CAP_NET_ADMIN for network admin tasks or CAP_SYS_ADMIN for lots of system actions). Programs can be run with only the capabilities they need, keeping things safer.
Permitted: Capabilities the process *can* use.
- Inheritable: Capabilities the process can *pass on* during an execve (when one program launches another).
Bounding: The maximum capabilities a process in the system can ever gain.
When a process runs a new program with execve(2), Linux combines these sets in a complex way to decide which capabilities the new program gets.
What Was the Problem?
You'd expect each new container to start with a clean, typical Linux environment – meaning no weird inheritable capabilities by default. Instead, before Docker Engine 20.10.14, Moby would accidentally *set some inheritable capabilities* for every new container.
Here’s why that’s a problem
- Suppose some file *inside* the container has inheritable or permitted capabilities (see with getcap).
- If a user or process without full privileges runs a program with inheritable file capabilities, those capabilities could become *active*, effectively “escalating” privileges within the boundaries of the container.
Normally, these inheritable capabilities wouldn't be set, so launching such programs wouldn't grant any new privileges. This bug created a non-standard environment that could trip up security assumptions, especially for those who use Linux’s users and groups to manage separation inside containers.
Suppose a file inside your container has the cap_net_admin capability set as *inheritable*
# Inside the container
$ getcap /usr/bin/foo
/usr/bin/foo cap_net_admin+ei
# 'e': effective, 'i': inheritable
A regular, unprivileged user runs this
$ /usr/bin/foo
Normally, because inheritable is empty, /usr/bin/foo can’t actually use cap_net_admin. But, because of the bug, the process *does* have that inheritable set, and so after an execve, /usr/bin/foo gets permitted the cap_net_admin capability. You’ve successfully escalated privileges within the container!
Here’s a snippet you can use to see what inheritable capabilities are set in a running Docker container:
$ docker run --rm -it ubuntu bash
root@abcdef:/# cat /proc/self/status | grep CapInh # CapInh = Inheritable
CapInh: 000000000000000 # Fixed versions show all zeros
On vulnerable (pre-20.10.14) containers, CapInh may show non-zero bits by default.
`bash
setcap cap_net_admin=ei /usr/bin/foo
`
2. Run this program as an otherwise-unprivileged user/process inside the container.
3. The program now receives the specified capability in its *permitted* set, letting it perform privileged actions within the container boundary.
The main risk: Any container where you *expect* users or processes to stay segregated by permissions could break down if executables with inheritable file caps are present.
Note: This does NOT let container users break out to the host or gain more privileges than the container's bounding set. The main target is workloads that rely on multi-user segmentation *inside* a container.
Real-World Impact
- Most containers run a single app and manage privilege separation outside the container, so most users are unaffected.
- If you use containers for multi-user applications (say, SSH with multiple UIDs, or a shared dev environment), you could be at risk.
The Fix
Moby/Docker Engine 20.10.14 changes how it launches containers: The inheritable capability set is now empty at container start, matching the standard Linux environment.
`bash
find / -type f -exec getcap {} \; 2>/dev/null
Workaround for Old Versions
If you can’t upgrade immediately, you can “zero” the inheritable set at container start using a tool like capsh:
ENTRYPOINT ["capsh", "--inh=x", "--", "-c", "/your-original-entrypoint.sh"]
This starts your main process with the inheritable set cleared.
References & More Reading
- Official Moby CVE-2022-24769 Security Advisory
- Moby Pull Request Fixing the Bug
- Understanding Linux Capabilities — Red Hat
- Docker 20.10.14 Release Notes
- capsh(1) - Linux capability shell
Conclusion
CVE-2022-24769 could affect any container that relies on Linux users and groups to keep processes separate. The odds of a real-world exploit are low if you manage all privileges at the container level (the Docker default). Still, upgrading Docker Engine is easy and closes off this corner-case – so don’t forget to update and, when in doubt, check your images for “sticky” capabilities!
If you want to learn more, head over to the official advisory or experiment yourself with getcap and capsh!
Stay safe — and keep your containers at their latest patch levels.
Timeline
Published on: 03/24/2022 20:15:00 UTC
Last modified on: 06/13/2022 11:15:00 UTC