DEV Community

Cover image for Opening Pandora's Container - How Exposing the Docker Socket Paves the Way to Host Control (Part 1)
David Gries
David Gries

Posted on

Opening Pandora's Container - How Exposing the Docker Socket Paves the Way to Host Control (Part 1)

In this three-part series, we'll explore some significant risks when working with Docker. The first part focuses on the Docker socket's role, the second will illustrate a real-world scenario of how attackers can compromise the host system, and the final post will provide hardening measures to mitigate these risks.

Role of the Docker Socket

If you've ever used Docker, you're likely familiar with its command-line interface (CLI). In simple setups, the CLI acts as the primary tool for interacting with the local Docker daemon - creating, starting, and stopping containers, etc. In more complex configurations, the CLI can also execute commands against remote targets. But how does it communicate with the daemon?

Docker utilizes a REST API for this interaction. By default, this API is not exposed over a TCP socket as you might expect; instead, it uses a Unix Domain Socket. (For a deep dive into inter-process communication with domain sockets, stay tuned for a future post.)

Let's take a look at the socket file on a default Debian installation:

admin@proxy:~$ ls -la /var/run/docker.sock 
srw-rw---- 1 root docker 0 Sep 20 13:37 /var/run/docker.sock
Enter fullscreen mode Exit fullscreen mode

As you can see, the file is writable by both the root user and docker group. This means that any member of that group has full access to this endpoint and can access the API.

For example, to get information about the installed engine without using the CLI you can query the socket using curl:

root@proxy:~# curl --silent --unix-socket /var/run/docker.sock "http://localhost/version" | python3 -m json.tool
Enter fullscreen mode Exit fullscreen mode
{
    "Platform": {
        "Name": "Docker Engine - Community"
    },
    "Components": [
        {
            "Name": "Engine",
            "Version": "27.3.1",
            "Details": {
...
Enter fullscreen mode Exit fullscreen mode

As the docker CLI is just a tool to interact with the backend, access to the socket provides the same level of (or even more) control over the system as using the CLI does.

Reasons for Exposing the Docker Socket

You may wonder why one would even want to expose the Docker socket when there are clearly risks involved. A popular usecase besides accessing remote Docker daemons (which you can actually expose over a TCP socket) are applications that either need control of the daemon to manage other containers, like for example Portainer, or tools that need information about containers for auto discovery purposes, like Traefik. The official Traefik documentation even includes a mounted docker socket in their deployment example:

services:
  reverse-proxy:
    image: traefik:v3.1
    command: --api.insecure=true --providers.docker
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      # Socket mounted into container running as 'root'
      - /var/run/docker.sock:/var/run/docker.sock
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

I've highlighted Traefik because it's a widely used reverse proxy that is frequently exposed directly to the public internet. This means that a vulnerability allowing remote code execution could grant attackers full access not only to the Traefik container, but also to the entire host system, if you don't take the necessary security measures.

In the upcoming parts, I'll provide a straightforward example demonstrating how an attacker can gain control of the Docker daemon and the host system from within a container. Additionally, I'll share strategies for hardening your systems to limit the impact of these kinds of threats. Stay tuned!

Top comments (0)