July 23, 2026
Docker Security: The Mistakes Everyone Makes
The most common Docker security mistakes that silently expose your infrastructure, secrets, and production workloads.

By Jaswinder Kumar
5 min read
Docker revolutionized software delivery.
Developers can package applications, dependencies, and configurations into portable containers that run consistently across environments. This portability is one of Docker's biggest strengths.
Unfortunately, it is also one of its biggest security challenges.
Many organizations adopt containers believing they are inherently secure. Containers provide isolation, but isolation is not security. A poorly configured container can become an entry point into your infrastructure, expose sensitive data, or allow attackers to move laterally through your environment.
The majority of container breaches are not caused by sophisticated zero-day vulnerabilities. They happen because of simple mistakes that teams make every day.
In this article, we'll explore the Docker security mistakes that appear repeatedly in real-world environments and how to fix them.
Mistake #1: Running Containers as Root
One of the most common Docker security mistakes is running applications as the root user.
Consider this Dockerfile:
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]FROM node:22
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]By default, the application runs as root.
Verify it:
docker exec -it container-id whoamidocker exec -it container-id whoamiOutput:
rootrootIf an attacker exploits the application, they immediately gain root privileges inside the container.
Although containers provide isolation, numerous container escape vulnerabilities have demonstrated that root inside a container can become root on the host.
Better Approach
Create a non-root user.
FROM node:22
RUN addgroup appgroup && adduser -D appuser -G appgroup
WORKDIR /app
COPY . .
RUN npm install
USER appuser
CMD ["node", "server.js"]FROM node:22
RUN addgroup appgroup && adduser -D appuser -G appgroup
WORKDIR /app
COPY . .
RUN npm install
USER appuser
CMD ["node", "server.js"]Now even if the application is compromised, the attacker's permissions are significantly restricted.
Mistake #2: Using the Latest Tag
Many teams deploy containers using:
image: nginx:latestimage: nginx:latestor
FROM ubuntu:latestFROM ubuntu:latestThis creates several problems:
- Non-reproducible builds
- Unexpected updates
- Security regressions
- Difficult troubleshooting
The image pulled today may not be the same image pulled tomorrow.
Better Approach
Use immutable versions.
FROM ubuntu:24.04FROM ubuntu:24.04Even better:
FROM ubuntu@sha256:<digest>FROM ubuntu@sha256:<digest>Image digests guarantee exact image integrity.
Mistake #3: Ignoring Image Scanning
A surprising number of organizations never scan container images.
Developers often assume official images are secure.
Reality says otherwise.
Even trusted base images can contain:
- Critical CVEs
- Outdated libraries
- Vulnerable packages
- Privilege escalation flaws
Example
Scan an image:
trivy image nginx:latesttrivy image nginx:latestExample findings:
CRITICAL: 2
HIGH: 15
MEDIUM: 48CRITICAL: 2
HIGH: 15
MEDIUM: 48Many vulnerabilities exist before you even add application code.
Recommended Scanners
- Trivy
- Grype
- Docker Scout
- Snyk
- Clair
Integrate scanning into CI/CD rather than performing it manually.
Mistake #4: Storing Secrets in Images
This mistake appears everywhere.
Example:
ENV AWS_ACCESS_KEY_ID=ABC123
ENV AWS_SECRET_ACCESS_KEY=xyz123ENV AWS_ACCESS_KEY_ID=ABC123
ENV AWS_SECRET_ACCESS_KEY=xyz123Or:
COPY .env .COPY .env .Even if removed later:
RUN rm .envRUN rm .envThe secret may still exist in previous image layers.
Attackers can recover secrets from image history.
Verify
docker history image-namedocker history image-nameor
docker image save image-namedocker image save image-nameThen inspect layers.
Better Approach
Use:
- Docker Secrets
- Kubernetes Secrets
- HashiCorp Vault
- AWS Secrets Manager
- Azure Key Vault
Secrets should never be embedded into images.
Mistake #5: Using Bloated Base Images
Developers often choose:
FROM ubuntuFROM ubuntuor
FROM centosFROM centoseven when the application needs only a few libraries.
Large images create:
- Larger attack surfaces
- More vulnerabilities
- Longer pull times
- Increased storage costs
Better Approach
Use minimal images:
FROM alpineFROM alpineor
FROM distroless/nodejsFROM distroless/nodejsBenefits:
- Fewer packages
- Reduced CVEs
- Smaller attack surface
- Faster deployments
Mistake #6: Exposing the Docker Socket
One of the most dangerous practices:
-v /var/run/docker.sock:/var/run/docker.sock-v /var/run/docker.sock:/var/run/docker.sockMany monitoring tools and CI/CD containers request this access.
Unfortunately, whoever controls the container effectively controls Docker.
An attacker can:
docker run -v /:/host alpinedocker run -v /:/host alpineThis grants access to the entire host filesystem.
At that point, the container boundary is essentially gone.
Better Approach
Avoid mounting the Docker socket whenever possible.
Use:
- Docker API proxies
- Rootless Docker
- Dedicated service accounts
- Restricted runtime permissions
Mistake #7: Running Privileged Containers
Some applications are started like this:
docker run --privileged myappdocker run --privileged myappThis grants nearly unrestricted access to the host.
Privileges include:
- Device access
- Kernel interactions
- Filesystem access
- Network modifications
Why It's Dangerous
A compromised privileged container can become a host compromise.
Better Approach
Grant only required capabilities.
Example:
docker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICEdocker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICEApply least-privilege principles.
Mistake #8: Not Limiting Resources
Containers without limits can consume:
- CPU
- Memory
- Disk
- Network resources
A simple bug can crash an entire node.
Example:
while true; do
echo "boom"
donewhile true; do
echo "boom"
doneThis may consume excessive resources.
Better Approach
Configure limits:
docker run \
--memory=512m \
--cpus=1 \
myappdocker run \
--memory=512m \
--cpus=1 \
myappKubernetes equivalent:
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1"resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1"Resource limits improve both security and stability.
Mistake #9: Ignoring Runtime Security
Most teams focus only on image scanning.
Security should continue after deployment.
Attackers operate at runtime.
Examples:
- Reverse shells
- Cryptominers
- Privilege escalation attempts
- Suspicious process execution
Image scanning cannot detect these activities.
Better Approach
Implement runtime detection:
- Falco
- Tetragon
- Sysdig Secure
- Aqua Runtime Protection
Example Falco rule:
- rule: Shell Spawned in Container
condition: container and shell_procs
output: Shell detected in container- rule: Shell Spawned in Container
condition: container and shell_procs
output: Shell detected in containerRuntime security provides visibility into active attacks.
Mistake #10: Trusting Public Images Blindly
Many teams use images from Docker Hub without verification.
FROM random-user/app:latestFROM random-user/app:latestThis is a major supply-chain risk.
Questions to ask:
- Who published it?
- Is it maintained?
- Is it signed?
- Has it been scanned?
Better Approach
Use:
- Official images
- Verified publishers
- Private registries
- Signed artifacts
Verify image signatures using Cosign:
cosign verify image-namecosign verify image-nameTrust should be earned, not assumed.
Mistake #11: Skipping Multi-Stage Builds
Many Dockerfiles accidentally ship:
- Build tools
- Package managers
- Compilers
- Source code
Example:
FROM golang:1.24
COPY . .
RUN go build app
CMD ["./app"]FROM golang:1.24
COPY . .
RUN go build app
CMD ["./app"]The final image contains everything.
Better Approach
Use multi-stage builds.
FROM golang:1.24 AS builder
WORKDIR /app
COPY . .
RUN go build -o app
FROM alpine
COPY --from=builder /app/app .
CMD ["./app"]FROM golang:1.24 AS builder
WORKDIR /app
COPY . .
RUN go build -o app
FROM alpine
COPY --from=builder /app/app .
CMD ["./app"]Benefits:
- Smaller images
- Fewer vulnerabilities
- Less attack surface
Mistake #12: Forgetting Security in CI/CD
Even perfectly secure Dockerfiles can be undermined by insecure pipelines.
Common issues:
- Unrestricted secrets
- Unsigned images
- No vulnerability scanning
- Untrusted pull requests
Secure Pipeline Checklist
✔ Scan images
✔ Scan Dockerfiles
✔ Verify dependencies
✔ Sign artifacts
✔ Generate SBOMs
✔ Enforce policy checks
Tools:
- Trivy
- Syft
- Grype
- Cosign
- Kyverno
- OPA
- Conftest
Docker Security Checklist
Before deploying a container, verify:
Build Phase
- Use trusted base images
- Pin image versions
- Use multi-stage builds
- Scan images
- Generate SBOMs
Runtime Phase
- Run as non-root
- Drop capabilities
- Avoid privileged mode
- Avoid Docker socket mounts
- Configure resource limits
Secrets Management
- Never hardcode credentials
- Use external secret stores
- Rotate secrets regularly
Supply Chain Security
- Verify image signatures
- Use trusted registries
- Sign container images
- Continuously monitor vulnerabilities
Final Thoughts
Docker provides an excellent foundation for modern application delivery, but security is not automatic.
The most dangerous Docker vulnerabilities are often self-inflicted:
- Running as root
- Hardcoding secrets
- Trusting unverified images
- Skipping image scanning
- Exposing the Docker socket
- Using privileged containers
Attackers don't need sophisticated exploits when basic security hygiene is missing.
The organizations that succeed with containers treat security as a continuous process spanning image creation, deployment, runtime monitoring, and supply-chain protection.
Docker security isn't about eliminating every risk.
It's about eliminating the mistakes everyone keeps making.
#Docker #CyberSecurity #DevOps #Kubernetes #CloudSecurity