Lesson 1 of 13 · 8 min read
What Containers Isolate, and What They Do Not
In this lesson
TL;DR: A container is an ordinary process given a private view of the system by namespaces (processes, network, mounts, users), limited by cgroups (CPU, memory), stripped of capabilities, filtered by seccomp and confined by AppArmor or SELinux. All containers on a host share one kernel, so a kernel vulnerability, a privileged container, a mounted container runtime socket or a host path mount can lead to the host. That is fine for running your own trusted services; it is a thin boundary for hostile code. gVisor interposes a user-space kernel, and microVMs (Firecracker, Kata) give each workload its own guest kernel behind hardware virtualisation.
Before you read
Pick an answer before you read further. The lesson below explains it, and guessing first, right or wrong, helps the explanation stay with you.
1A team runs an agent's code-execution tool in a Docker container on the application server. To let the agent build images, they mount /var/run/docker.sock into the container. What have they given the agent?
What a container actually is
There is no "container" object in the Linux kernel. A container runtime starts an ordinary process and applies several kernel features:
| Feature | What it restricts |
|---|---|
| Namespaces (pid, net, mnt, uts, ipc, user, cgroup) | What the process can see: its own process tree, network stack, filesystem view, hostname, and optionally mapped user IDs |
| cgroups | How much CPU, memory, I/O and how many processes it can use |
| Capabilities | Which root privileges remain; runtimes drop most by default |
| seccomp | Which system calls it may make; default profiles block dozens of risky ones |
| AppArmor / SELinux | Mandatory access control over files, mounts and operations |
| Read-only root, no new privileges | Prevents modifying the image and gaining privileges via setuid binaries |
Together these make a container look like its own machine. The crucial fact is that every system call still goes to the same host kernel.
How containers fail as a security boundary
Kernel vulnerabilities. The host kernel exposes a large attack surface, hundreds of system calls, through which a contained process can attack it. A privilege-escalation bug in the kernel is usually a container escape.
Misconfiguration, which is far more common:
--privilegedgrants nearly all capabilities and device access, removing most isolation.- Mounting the container runtime socket (
docker.sock, containerd's socket) lets the container start new privileged containers. - Host path mounts of
/,/etc,/var/runor credential directories expose the host directly. - Adding capabilities such as
CAP_SYS_ADMIN, disabling seccomp or AppArmor, sharing the host network or PID namespace. - Running as root without user namespaces, so a breakout lands as root on the host.
The runtime itself. Escapes do not come only from misconfiguration. The low-level runtime that sets up containers, runc, has had several:
| CVE | Published | What went wrong | Fixed in |
|---|---|---|---|
| CVE-2019-5736 | February 2019 | A process in a container could overwrite the host's runc binary and gain root on the host | runc after 1.0-rc6 (Docker 18.09.2) |
| CVE-2024-21626 ("Leaky Vessels") | January 2024 | A leaked internal file descriptor let a new container process start with its working directory on the host filesystem (CVSS 3.1: 8.6) | runc 1.1.12 |
| CVE-2025-31133 and CVE-2025-52565 | November 2025 | Races in how masked paths and /dev/console were mounted could be abused to escape (CVSS 4.0: 7.3 and 8.4) | runc 1.2.8 and 1.3.3 |
The lesson is operational: a patch deadline for the container runtime is part of the isolation design.
Root without user namespaces. If a process escapes as user 0 and the container did not use a user namespace, it is root on the host. Kubernetes made user namespaces generally available in version 1.36 (April 2026), turned on per pod with hostUsers: false, after enabling them by default in beta from 1.33. With them, root inside the container maps to an unprivileged user on the host.
Shared resources. Containers on one host share the kernel, page cache and often devices such as GPUs, which creates side channels and resource contention.
What the default seccomp profile actually blocks
Docker's default seccomp profile is an allowlist that disables around 44 of more than 300 system calls. The blocked ones are telling: mount; the kernel keyring calls (add_key, keyctl, request_key), because the keyring is not namespaced; the io_uring calls, which Docker blocks because of vulnerabilities that have been used to break out of containers; creating new namespaces with unshare or clone; and reboot. Everything else, including most of the kernel, remains reachable. A profile built for the specific workload can be much tighter.
Stronger boundaries
Protecting: Host and other tenants
- 1
1 · Hardened config
no socket, no host mounts
- Stops: Uses a mounted runtime socket
- Stops: Reads a host path mount
- 2
2 · gVisor user-space kernel
small host syscall surface
- Stops: Exploits a kernel bug
- 3
3 · MicroVM
separate guest kernel
- Stops: Exploits a kernel bug
- 4
4 · Network policy / egress proxy
deny by default
- Stops: Reaches internal services
- gVisor runs a user-space kernel (the Sentry) that implements Linux system calls itself and makes only a small set of calls to the host kernel. A kernel bug reachable from the workload is usually in gVisor's code, not the host's.
- MicroVMs such as Firecracker (used by AWS Lambda and Fargate) and Kata Containers run each workload in a lightweight virtual machine with its own guest kernel, behind hardware virtualisation. Escaping requires a hypervisor or virtual-device bug, a much smaller surface.
- Full VMs give the strongest conventional isolation at higher cost.
The trade-off is overhead and compatibility: gVisor adds system call latency and does not support every feature; microVMs add startup time and memory; GPUs are hard to share safely across any of them.
The stronger boundaries, with numbers
| Boundary | Key facts | Stated limits |
|---|---|---|
| gVisor | No workload system call passes directly to the host; the Sentry makes a minimal set of host calls and cannot open files or sockets itself unless configured to; the Systrap platform has been the default since June 2023 | Its own documentation says it does not protect against hardware side channels, relies on the host for resource limits, and is "not a substitute for a secure architecture" |
| Firecracker | About 50,000 lines of Rust, 96% fewer than QEMU; emulates only network and block devices, a serial console and part of a keyboard controller; its jailer limits the VMM to 24 system calls and 30 ioctls; boots in about 125 ms with under 5 MiB of VMM overhead | No GPU passthrough |
| Kata Containers | Runs pods in VMs using QEMU, Cloud Hypervisor, Firecracker, Dragonball or StratoVirt | Only the QEMU option is listed as supporting GPUs and confidential computing (Intel TDX, AMD SEV-SNP) |
GPUs: the AI-specific escape surface
AI platforms add a component most container discussions skip: the NVIDIA Container Toolkit, which prepares GPU access when a container starts. It has had two critical host escapes in two years.
- CVE-2024-0132 (September 2024, CVSS 3.1: 9.0): a time-of-check to time-of-use flaw meant a crafted image could reach the host filesystem in the default configuration. It affected toolkit versions up to 1.16.1 and GPU Operator up to 24.6.1. Found by Wiz.
- CVE-2025-23266 (July 2025, CVSS 3.1: 9.0, "NVIDIAScape"): a flaw in a container initialisation hook let a malicious image run code with elevated privileges on the host. It affected versions up to 1.17.7 and was fixed in 1.17.8, after being demonstrated at Pwn2Own Berlin in May 2025.
Both were reachable by an image, which is exactly what a platform that runs customer models or customer containers accepts. GPU sandboxing options are narrower too: Google's GKE Sandbox supports GPUs with gVisor only for CUDA on a subset of models and notes that microVMs do not support GPUs.
Shared GPU node, unpatched toolkit
Customer image scheduled on shared node
Toolkit hook runs at container start
toolkit 1.17.7
Host code execution, other tenants' weights
Outcome, unsafe: One image, every tenant
The escape came through GPU setup, not the workload's own code.
Per-tenant node, patched, image policy
Image signature and allowlist checked
Toolkit 1.17.8 or later, CDI mode
patch deadline tracked
Node identity reaches one tenant only
Outcome, safe: An escape stays inside one tenant
Isolation is designed for the case where the boundary fails.
Shared GPU nodes
When images from many tenants share a node, a toolkit escape reaches all of them.
Worked example: CPU jobs and GPU jobs on one platform
A platform runs 2,000 short Python jobs an hour written by an agent, and also loads customers' fine-tuned models on GPUs. The sizing figures are illustrative; the per-VM figures are Firecracker's published ones.
- CPU jobs go in a microVM per session. At about 125 ms per boot, 2,000 boots cost about 250 seconds of start-up per hour in total. If 200 run at once, VMM overhead is about 1,000 MiB, plus each guest's own memory.
- GPU jobs cannot use Firecracker. The choices are Kata with QEMU and GPU passthrough, gVisor with supported CUDA GPUs, or a dedicated node per tenant.
- Either way, the GPU nodes run the container toolkit, so its version and patch deadline belong in the design review alongside the boundary choice.
- 1
1 · Configuration
Privileged mode, runtime socket, host mounts
- Most common cause
- Caught by admission policy
Remove before anything else
- 2
2 · Container runtime
runc and its setup steps
- Escapes in 2019, 2024 and 2025
- Patch deadlines matter
Trusted code with bugs
- 3
3 · GPU setup
Container toolkit hooks
- Two CVSS 9.0 escapes
- Reachable from an image
AI-specific
- 4
4 · Host kernel
Every allowed system call
- Default profile blocks about 44
- User namespaces limit the landing
Shared by all containers
- 5
5 · Hardware
Caches, GPUs, side channels
- Not addressed by gVisor
- Separate hosts for high risk
Below every software boundary
Configuration and runtime
Misconfiguration is the usual way out, but the runtime itself has had real escapes.
Choosing
| Workload | Reasonable boundary |
|---|---|
| Your own services, reviewed code | Hardened containers: non-root, read-only, default seccomp, no extra capabilities |
| Third-party code you vetted | Hardened containers, separate nodes for sensitive workloads |
| Untrusted or model-generated code | gVisor or microVMs, plus no credentials and egress control |
| Multi-tenant code execution for customers | MicroVMs per tenant or per session, separate hosts for high-risk tenants |
Why this matters for AI systems
Agents that write and run code, data-analysis tools that execute model-generated Python, and platforms that load customer-provided models all run code nobody reviewed. Containers alone are a thin boundary for that, and the common shortcuts (mounting the Docker socket, sharing the host network, passing cloud credentials) remove even that. The sandboxing lesson builds the full design.
Misconceptions interviewers listen for
- "Containers are a security boundary like VMs." They share the host kernel, and runc itself had escapes in 2019, 2024 and 2025.
- "gVisor stops everything." By its own documentation it does not address hardware side channels or resource exhaustion.
- "Firecracker gives me isolated GPUs." It has no GPU passthrough.
- "A non-root user in the image is enough." Without user namespaces, an escape as root is root on the host.
- "The default seccomp profile blocks the dangerous calls." It blocks about 44 of 300+.
What if · interview follow-ups
Hold your answer as the constraints change
You are designing isolation for a platform that runs agent-generated code and customers' fine-tuned models on shared Kubernetes clusters with GPU nodes. The interviewer probes each boundary.
Start here
Why is mounting the container runtime socket into a container equivalent to giving it root?
What can the runtime API do?
The socket exposes the runtime's API, which can start new containers with any settings, including privileged mode and host filesystem mounts. Anything that can talk to it can create a container that owns the host, so the strength of the original container's isolation no longer matters.
Carry it forwardAccess to the runtime API is root on the host.
Weak answerSaying read-only mounting of the socket makes it safe.
Constraint changes
With privileged mode, the runtime socket and host mounts all removed, what escape path remains?
Bugs in trusted components.
Bugs in the kernel or the runtime, such as runc's 2024 leaked file descriptor escape. Mitigate with patch deadlines for the runtime and kernel, user namespaces so an escape does not land as host root, a seccomp profile tighter than the default, and a stronger boundary such as gVisor or microVMs for hostile code.
Carry it forwardHardening removes misconfiguration; runtime and kernel bugs remain.
Weak answerClaiming hardened containers cannot be escaped.
Constraint changes
Hostile code now needs a GPU. What changes in the design?
Which boundaries support GPUs, and what new component runs?
Firecracker is out because it has no GPU passthrough. The options are Kata with QEMU passthrough, gVisor's CUDA support on certain GPUs, or dedicated nodes per tenant. The NVIDIA container toolkit becomes part of the attack surface: it had two CVSS 9.0 host escapes reachable from container images, so its version and patching are part of the design.
Carry it forwardGPU workloads change the boundary options and add the toolkit to the threat model.
Weak answerAssuming the CPU sandbox design carries over.
Constraint changes
A customer uploads a container image your GPU nodes will run. What do you verify before it starts?
Toolkit version, image policy, node scope.
That the toolkit and GPU Operator are at fixed versions (1.17.8 or later for the 2025 flaw), that the CDI configuration is used, that images pass a signature or allowlist policy, that image-controlled settings cannot reach privileged hooks, and that the node is dedicated to that tenant or otherwise cannot reach other tenants' data.
Carry it forwardCustomer images are untrusted input to privileged node setup.
Weak answerScanning the image for malware and calling it safe.
Constraint changes
How would you show an auditor that an escape from one tenant cannot reach another tenant's model weights?
Assume the boundary fails; what still holds?
Use per-tenant nodes or VMs with no shared GPU, node identities that can read only that tenant's storage, network policy between tenants, and telemetry for escape signs such as unexpected host processes. Then back the claim with red-team evidence. Isolation is something you test, not a configuration you assert.
Carry it forwardDesign so a failed boundary still cannot reach other tenants, and test it.
Weak answerPointing to the container configuration as proof.
Now defend it
As the defender, what would suggest a container escape attempt on a node?
Processes on the host whose parents are container runtimes, writes to runtime binaries, unexpected mounts, seccomp denials for blocked calls such as io_uring or keyring operations, privileged containers or host mounts created outside admission policy, and GPU nodes running toolkit versions below the fixed release.
Primary references
References for the mechanisms discussed above, accessed 6 November 2026:
How this shows up in interviews
"Containers, gVisor, microVMs, VMs: where is each isolation boundary?" is a standard infrastructure question for AI security roles. Strong answers name the kernel features, say plainly that containers share the host kernel, list the misconfigurations that defeat them, and choose a boundary by how much the code is trusted. Expect a follow-up about GPUs.
Say it in 30 seconds: "A container is a process with namespaces, cgroups, dropped capabilities, seccomp and an LSM, all on a shared host kernel. That's fine for our own code, but a kernel bug or a misconfiguration like privileged mode, a mounted Docker socket or a host mount gets you to the host. For untrusted or model-generated code I use gVisor, which interposes a user-space kernel, or a microVM like Firecracker with its own guest kernel, and I still remove credentials and lock down egress."
Check yourself
Say or write your answer first, then reveal. Explaining it from memory, in your own words, is the skill an interviewer is checking.
1Why does running a container as a non-root user help even though the container already has namespaces?
2A microVM sandbox for agent code has full outbound internet access and an environment variable holding a cloud API key. Is it a strong sandbox?
3Name two NVIDIA Container Toolkit vulnerabilities and why they matter for AI platforms.
4What do Kubernetes user namespaces change about a container escape?