Blog
Defending Against Container Escape: A Practical Guide to Docker Isolation for Multi-Tenant Hosting
Learn how to secure Docker containers against escape vulnerabilities and isolation failures in multi-tenant environments with concrete steps and examples.

Summary
Docker containers share the host kernel, making isolation critical—especially in multi-tenant hosting where a single container escape can compromise all tenants. Many developers assume containers are perfectly isolated virtual machines, but reality is different. This article explains the Linux kernel features behind Docker isolation (namespaces, cgroups) and the attack vectors that threaten them. You'll learn practical steps to harden your Docker setup: limiting privileges, using secure runtime, scanning images, and implementing network segmentation. By following a real-world example of a multi-tenant WordPress hosting provider, you'll see how to apply these defenses. We also cover caveats like performance trade-offs and use of seccomp/AppArmor. The goal is to give you a robust isolation strategy that prevents container escapes and keeps your tenants safe.
Introduction
If you run a multi-tenant hosting platform—whether it’s shared WordPress hosting, a SaaS application, or a dev environment service—container escape is the nightmare scenario. A vulnerability in the kernel or a misconfiguration can let one tenant break out of their container and access other tenants’ data or the host itself. Docker’s isolation relies on Linux kernel features like namespaces and cgroups, but out-of-the-box configurations are often insufficient for robust security. This article will walk you through the attack vectors and provide actionable steps to lock down your Docker containers, illustrated with a real-world multi-tenant WordPress example. For a broader look at production orchestration, see our guide on Orchestrating Production-Ready Containerized Applications.
Understanding Docker Isolation
Docker containers use Linux namespaces to provide process-level isolation: PID namespaces isolate process trees, network namespaces separate network interfaces, mount namespaces isolate filesystem mounts, and user namespaces allow mapping container root to an unprivileged host user. Control groups (cgroups) limit resource usage such as CPU, memory, and disk I/O. These features together create a “sandbox” around each container. However, unlike a virtual machine that runs a separate kernel, containers share the host kernel. This means a vulnerability in the kernel (e.g., CVE-2022-0492) can be exploited to break out of the container’s namespace isolation. Additionally, misconfigurations like running containers as root inside the container, giving the container all capabilities, or not dropping unnecessary Linux capabilities can widen the attack surface.
Attack Vectors
Common attack vectors include:
- Kernel exploits: Exploiting a bug in the host kernel to gain host access.
- Privileged containers: Running with
--privilegedgrants all capabilities and bypasses most isolation. - Capability abuse: Even without full privileged mode, a container with dangerous capabilities like
CAP_SYS_ADMINorCAP_NET_ADMINcan mount filesystems or manipulate network settings. - Insecure image practices: Using base images with known vulnerabilities or including unnecessary tools like compilers or shell interpreters.
- Shared mount namespaces: Mounting host directories into containers can allow escape if not read-only.
Practical Security Steps
1. Run Containers as a Non-Root User
By default, Docker runs containers as root inside the container. If an attacker gains root inside the container, they have more leverage. Create a user in your Dockerfile and use the USER directive. Also, avoid using the --user flag in Docker Compose to map to an arbitrary host user if possible.
2. Drop All Capabilities and Add Only Needed
Linux capabilities break down superuser privileges into smaller units. In Docker Compose, use cap_drop: ALL then cap_add only the required ones (e.g., NET_BIND_SERVICE). Avoid dangerous capabilities like SYS_ADMIN, NET_ADMIN, SYS_PTRACE.
3. Use Read-Only Root Filesystem
Set read_only: true in your container definition. This prevents attackers from writing to the container’s filesystem. If your app needs to write temporary files, mount a tmpfs volume at that location.
4. Enable User Namespace Remapping
User namespace remapping maps the container’s root user to a non-root host user. This adds a layer of isolation, as even if a container root breaks out, they will have the privileges of the remapped user. Enable it in /etc/docker/daemon.json with "userns-remap": "default". Be aware that this can complicate volume permissions. For more details, see Mastering Docker Isolation for Secure and Efficient Web Hosting.
5. Apply Seccomp and AppArmor/AppArmor Profiles
Seccomp restricts the system calls a container can make. Docker provides a default seccomp profile that blocks dangerous syscalls. You can also craft custom profiles. Similarly, AppArmor (or SELinux) provides mandatory access control. Use AppArmor to confine your container to a minimal set of allowed operations. The security profile can be set via security_opt in Docker Compose.
6. Use Minimal Base Images and Scan for Vulnerabilities
Choose small images like Alpine or Distroless that have a smaller attack surface. Regularly scan images with tools like Docker Scout, Trivy, or Clair. Integrate scanning into your CI/CD pipeline to prevent vulnerable images from being deployed.
7. Network Segmentation with Custom Bridge Networks
Create separate bridge networks for each tenant or application tier. This limits east-west traffic. In Docker Compose, define networks and isolate services. Use internal: true if a service doesn’t need outgoing Internet access. Firewall rules on the host further restrict inter-container traffic.
8. Limit Resources with Cgroups
Set CPU and memory limits in Docker Compose using deploy.resources.limits. This prevents a compromised container from launching a resource exhaustion attack. Additionally, set kernel_memory and memory_reservation for finer control.
Real-World Example: Multi-Tenant WordPress Hosting with Docker Compose
Consider a scenario where you host multiple WordPress sites for different clients, each in its own Docker container. An insecure setup might look like:
version: '3'
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- ./wp-content:/var/www/html/wp-content
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: somewordpress
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
This setup is vulnerable: the WordPress container runs as root inside, has all capabilities (since none are dropped), mounts a host directory with write access, and has unrestricted network access.
Now let’s harden it:
version: '3'
services:
wordpress:
image: wordpress:latest
user: www-data
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /var/www/html/wp-content/plugins
security_opt:
- seccomp=seccomp-profile.json
- apparmor=wordpress-profile
networks:
- frontend
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wp-uploads:/var/www/html/wp-content/uploads
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
db:
image: mysql:5.7
user: mysql
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
networks:
- backend
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: somewordpress
volumes:
- db_data:/var/lib/mysql
deploy:
resources:
limits:
cpus: '0.25'
memory: 128M
networks:
frontend:
driver: bridge
internal: false
backend:
driver: bridge
internal: true
volumes:
wp-uploads:
db_data:
Key improvements:
- Both containers run as non-root users (
www-dataandmysql). - All capabilities dropped, only
NET_BIND_SERVICEadded. - WordPress filesystem is read-only except for a tmpfs mount and an uploads volume.
- Seccomp and AppArmor profiles are applied (you’d need to provide custom profiles).
- Separate networks isolate web from database, with database network internal.
- Resource limits prevent resource exhaustion.
For more on WordPress-specific Docker hardening, see Docker for WordPress: Why Isolated Containers Change Everything.
Caveats
- User Namespace Remapping: While powerful, it breaks volume mounting because the remapped host UID is not the same as the container UID. You may need to pre-create directories with the correct permissions or use Docker volumes with remapping support.
- Seccomp/AppArmor Profiles: Custom profiles require understanding your application’s syscall and file access patterns. Overly restrictive profiles can break functionality. Test thoroughly.
- Performance: Additional security layers like seccomp and AppArmor have minimal overhead, but resource limits and read-only filesystems may affect write-heavy applications.
- Orchestration Complexity: In a multi-tenant environment, managing per-tenant Docker Compose files can become unwieldy. Consider using a higher-level orchestration tool like Kubernetes, but that introduces its own security considerations.
Conclusion
Container escape is a real threat in multi-tenant Docker hosting, but it is preventable. By understanding the isolation mechanisms and applying defense-in-depth—dropping capabilities, running as non-root, enabling user namespaces, seccomp, AppArmor, network segmentation, and regular image scanning—you can dramatically reduce the risk. Remember that Docker’s default settings are not production-ready for multi-tenant workloads. Implement these steps today to protect your tenants and your infrastructure. For a comprehensive overview of Docker security best practices, refer to Securing Your Web Applications with Docker: A Practical Guide to Isolation and Best Practices.
Sources (5)
- Docker and Container Isolation - Medium
- What is container isolation? Mechanisms, limitations, and secure runtimes | Blog - Northflank
- Container Isolation Explained for Kubernetes and Beyond - Edera
- Docker Security: 5 Risks and 12 Best Practices for Securing Your Containers - Tigera.io
- 9 Security Best Practices for Docker Containers - Kinsta®

