Docker Security for Small Teams: 10 Things You're Probably Getting Wrong

Docker's promise is isolation. Your application runs in a container, separate from the host, separate from other containers. But that isolation is only as strong as your configuration, and most small

Docker's promise is isolation. Your application runs in a container, separate from the host, separate from other containers. But that isolation is only as strong as your configuration, and most small teams leave the defaults in place without understanding what those defaults allow.

Here are ten Docker security mistakes we see constantly, along with straightforward fixes that do not require a security team or enterprise tooling.

1. Running Containers as Root

By default, processes inside Docker containers run as root. If an attacker exploits a vulnerability in your application, they have root access inside the container. Combined with a container escape vulnerability, that becomes root on the host.

Fix: add USER nonroot to your Dockerfile. Create a non-root user and switch to it before the CMD instruction. Most applications do not need root.

2. Using latest Tags

FROM python:latest means your build uses whatever version of Python was most recently pushed. This creates unreproducible builds, unexpected breakage, and potential supply chain attacks if a malicious image is pushed to latest.

Fix: pin specific versions. FROM python:3.12-slim-bookworm is reproducible, auditable, and predictable.

3. Exposing the Docker Socket

Mounting /var/run/docker.sock into a container gives that container full control over the Docker daemon — it can create, start, stop, and delete any container on the host. This is root-equivalent access.

Fix: never mount the Docker socket unless absolutely necessary (CI/CD runners, monitoring tools). When required, use a socket proxy that restricts operations.

4. Storing Secrets in Images

Secrets baked into Docker images persist in layer history. Even if you delete a secret in a later layer, it remains in the build cache and can be extracted with docker history.

Fix: use environment variables, Docker secrets (Swarm), or mounted secret files. Never COPY .env files or embed API keys in Dockerfiles.

5. Publishing All Ports

docker run -p 5432:5432 publishes your database port to every network interface on the host, including the public internet. Many production databases have been compromised this way.

Fix: bind to localhost. docker run -p 127.0.0.1:5432:5432 makes the port accessible only from the host machine. Use Docker networks for container-to-container communication instead of published ports.

6. No Resource Limits

Without resource limits, a single container can consume all CPU and memory on the host, starving other containers. A cryptocurrency miner in a compromised container can silently eat your entire server.

Fix: set limits in docker-compose: deploy.resources.limits.memory: 512m and deploy.resources.limits.cpus: '1.0'.

7. Ignoring Image Scanning

Base images contain packages with known vulnerabilities. A python:3.12 image includes the full Debian distribution, with hundreds of packages you do not use and dozens of known CVEs.

Fix: use slim or Alpine-based images. Run docker scout cves or Trivy to scan for known vulnerabilities before deploying.

8. No Health Checks

Without a HEALTHCHECK instruction, Docker considers a container healthy if the process is running, even if the application is deadlocked, out of memory, or returning 500 errors.

Fix: add a HEALTHCHECK that tests actual application functionality. HEALTHCHECK CMD curl -f http://localhost:8080/health || exit 1

9. Using Host Network Mode

network_mode: host removes all network isolation. The container shares the host's network stack, can bind to any port, and can see all network traffic. This eliminates one of Docker's primary security benefits.

Fix: use bridge networks (the default) or custom Docker networks. Only use host networking when you have a specific performance requirement and understand the security implications.

10. Not Monitoring Container Activity

If you do not know what your containers are doing, you will not notice when one is compromised. Container logs, resource usage, and network activity should be monitored.

Fix: use docker stats, forward container logs to a central location, and set up alerts for unexpected resource consumption. Tools like CronPing can monitor container health endpoints on a schedule and alert you when something goes wrong.

The Pattern

None of these fixes are expensive or complex. They are configuration changes and good defaults. The problem is not that Docker security is hard — it is that insecure defaults are easy and nobody forces you to change them.

Start with these ten. Your containers will be more secure than 90% of production Docker deployments, without buying a single tool.

Read more