Skip to content
Sedat Özdemir
Writing

container-security

From Docker Socket to Root Shell: Is Container Isolation an Illusion?

A deep dive into how misconfigured Docker containers, privileged flags, and exposed sockets turn your 'secure' environment into a playground for Red Teamers.

Sedat Özdemir
· 3 dk read

Running the command docker run --privileged --net=host --pid=host -it alpine /bin/sh is the moment your container stops being an isolation layer and becomes a wide-open highway straight to the heart of the host OS. If I'm on a Red Team engagement and find a container running with these parameters, I can just sit back and start sipping my coffee—because I already own the machine.

The False Security of Isolation

Many of my developer buddies still think containers are 'lightweight virtual machines.' They aren't. A container is nothing more than a collection of Linux kernel features—specifically namespaces and cgroups. If you don't configure these features correctly, that box you think is 'secure' is actually just a paper tiger.

As a Red Teamer, one of the first things I check for is whether the /var/run/docker.sock file is mounted inside the container. Usually done for monitoring tools or CI/CD agents, this mistake gives an attacker full control over the Docker API.

Consider this scenario: You're inside a container, you run ls -la /var/run/docker.sock, and there it is. That’s the moment the alarm bells should be ringing for any sysadmin. With a simple curl request, I can spin up a new container on the host and mount the host's root directory (/) directly into it:

# Defanged example attack concept
curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" \
  -d '{"Image": "alpine", "HostConfig": {"Binds": ["/:/mnt/host"]}}' \
  -X POST http://localhost/v1.41/containers/create

After this request, all I have to do is start that container, navigate to /mnt/host/etc/shadow, and grab the hashes. Congratulations, I'm now the owner of your host system.

Capabilities: Unnecessary Power is Not Power

The Linux kernel breaks down root privileges into smaller units called 'capabilities.' When you give a container the CAP_SYS_ADMIN capability, you're essentially giving it permission to do almost anything.

A frequent mistake I see is developers enabling all capabilities through 'trial and error' just to get an app running. From a Red Team perspective, capabilities like CAP_SYS_RAWIO or CAP_SYS_PTRACE are perfect gifts for kernel-level manipulation.

If you want to harden an image, your first rule must be 'Least Privilege.' Drop every capability you don't absolutely need:

# docker-compose.yml or Kubernetes Manifest example
securityContext:
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE

Time Bombs Inside Your Images

It’s not just the runtime; the image itself is a risk. When you write FROM python:latest, do you actually know what's being pulled? Are you tracking which libraries in that image have critical vulnerabilities (CVEs)?

In projects I've worked on, I often see this: The application code is solid and secure, but the base image is built on a version of Debian from three years ago that's riddled with vulnerabilities.

As an attacker, once I land inside a container, the first thing I do is look for these low-hanging fruits to escalate my privileges or pivot further into your network.

Related posts