Skip to content
Sedat Özdemir
Writing

container-security

A Tale of Isolation and Container Chaos: Where Do We Go Wrong While Getting 'Dockerized'?

Think containers are inherently secure? Think again. From bloated base images to secret leaks in layers, let's explore how 'dockerized' applications actually fall apart and how to fix them.

Sedat Özdemir
· 4 dk read

Have you ever reached the point of wanting to bite your keyboard after seeing thousands of 'High' and 'Critical' findings in a CVE scan while your Docker image was building?

Hey everyone, Sedat here. Today, let's talk about containers—but not that rose-colored world you see in documentation. Let's talk about the cold, hard facts we encounter in the field during tests we conduct under the testCompany roof. You know, those famous boxes where we say, 'Man, the container is already isolated, nothing will happen,' and then turn our backs only to find ourselves in deep trouble.

Container technology saved our lives, I'll admit that. it solved dependency issues and ended the 'it worked on my machine' meme. But let’s be honest; most of us think containers are a security layer. In reality, a container is just a glorified process. We live in a kernel-sharing world, and if that kernel gets hit, we all go down.

The First Mistake: Being Generous with the 'Base Image'

It usually goes like this: My developer friend wants to try something quickly and pulls FROM ubuntu:latest or FROM python:3.9. Oh, it's beautiful—it has everything: curl, wget, netcat, maybe even gcc! This is exactly where we, as the Red Team, love to be. Once we infiltrate that container somehow, these pre-installed tools become a 'post-exploitation' gold mine for us.

Look, as an attacker, I don't want to deal with downloading my own tools once I'm in. If curl is already on the system, getting a reverse shell takes only a few seconds.

Bad Example (Defanged Dockerfile):

# The all-inclusive package, like an open buffet
FROM node:14
WORKDIR /app
COPY . .
RUN npm install
# Running the app as root? Great idea!
CMD ["node", "server.js"]

This image is probably 1GB in size and contains at least 500 known vulnerabilities (CVEs). What should we do instead? Use minimalist approaches like 'Distroless' or 'Alpine,' of course. I'm talking about an image that doesn't even have a shell inside. Imagine this: I get inside, but I can't even type ls. That’s real security.

Secret Management: Diamonds in the Trash Can

One of the things we profit from the most in Red Team operations is the docker history command. A friend says, 'Oh, I was in a hurry, I wrote the API key as an ENV, but I deleted it later.' Well, sorry to break it to you. Docker has a layered structure. Even if you delete it in the top layer, it stays in that bottom layer forever.

Seemingly Innocent But Dangerous Command:

# Imagine this being run from the terminal
docker build --build-arg API_KEY="super-secret-key-123" -t my-app .

The moment I type docker history my-app after this, I see that key clear as day. In our tests at testCompany, we've 'pwned' entire cloud infrastructures because of secrets like these leaking from CI/CD pipelines. Never carry your secrets inside a Dockerfile or as build arguments. Use Vault for this, or if you don't have that, at least mount them securely at runtime.

The Passion for Being 'Root' and Capabilities

The user inside a container is usually root by default. This is one of the biggest 'misconfigurations' we see. If an attacker finds a vulnerability in your application (like a Remote Code Execution), they land directly with root privileges. From there, escaping to the host machine or mounting the Docker socket (/var/run/docker.sock) becomes child's play. Always use a non-privileged user and only give the container the specific Linux 'capabilities' it actually needs to run.

Related posts