Docker from First PrinciplesPost 13 of 18 · 18 of 18 written

13. Security

Docker · 13 of 182 min readOct 2026

Containers isolate well enough for most workloads, but more weakly than virtual machines, because every container shares the host kernel. The real-world risks are rarely exotic escapes; they’re running as root, mounting the Docker socket, leaking secrets into layers, publishing ports to the internet, and trusting unverified images and model files.

The main risks and their fixes

  • Root in the container is root on the host’s kernel. Without user namespaces, UID 0 inside is UID 0 outside; only namespaces, capabilities and seccomp stand between it and the host. Set USER in images, and consider rootless Docker, Docker’s userns-remap, or Podman’s rootless mode, which map container root to an unprivileged host user.
  • Mounting docker.sock hands over the host. A container with -v /var/run/docker.sock:/var/run/docker.sock can start privileged containers and read any file on the host. CI runners, dashboards and some agent frameworks ask for this; know that you’re granting root.
  • --privileged disables isolation. If something needs one device or one capability, grant exactly that with --device or --cap-add.
  • Least privilege by default. For services, --cap-drop ALL (then add back only what’s needed), --security-opt no-new-privileges, and --read-only with a tmpfs for /tmp remove most of what an attacker could use.
  • Secrets leak through layers and metadata. ARG and ENV values show up in docker history and docker inspect. COPY .env followed by RUN rm .env leaves the file in the earlier layer. Use BuildKit secret mounts at build time and runtime injection afterwards.
  • Published ports bypass host firewalls on Linux (Part 8). Bind internal services to 127.0.0.1 and put authentication in front of anything public.

Supply chain

Every FROM trusts someone else’s code. Prefer official or verified publishers, pin digests, and rebuild regularly to pick up security patches. Scan images with Docker Scout, Trivy or Grype. Generate a software bill of materials (docker buildx build --sbom=true) and provenance attestations, and sign images with Sigstore’s cosign when others will consume them.

Model files are code too

PyTorch’s classic .pt and .bin checkpoints use Python’s pickle format, which can execute arbitrary code when loaded. Prefer safetensors files, and load anything else with torch.load(..., weights_only=True), which recent PyTorch versions use by default. Treat a random checkpoint from the internet like a random executable.

Sandboxing LLM-generated code

Agents that run model-written code need stronger isolation than a plain container offers. Layer the defences: no network (--network none) or an egress allowlist, a read-only root filesystem, a non-root user, tight CPU, memory and PID limits (--pids-limit), a short timeout, and a stronger runtime. gVisor (--runtime=runsc) intercepts system calls in a user-space kernel; Firecracker and Kata Containers run each container in a lightweight VM. Hosted code-execution sandboxes for agents are built on these same pieces.