InitRunner

Runtime Sandbox

Since v2026.4.16, tool subprocesses run under kernel-level isolation, outside the initrunner process. This is distinct from the PEP 578 audit-hook sandbox (security.tools.audit_hooks_enabled), which runs inside the Python interpreter.

Pick one of three backends:

  • Bubblewrap — Linux user namespaces. No daemon, no Docker, no root. Default on Linux.
  • Docker Sandbox — Containers via the Docker daemon. Works on macOS, Windows, and Linux. Supports pinned images and bridge networking.
  • SSH Backend — Remote execution on an existing host via OpenSSH (since v2026.5.1). Not a kernel sandbox; use it to choose where code runs, not for containing untrusted code.

backend: auto tries bwrap on Linux and falls back to Docker. SSH is opt-in only (backend: ssh) because it needs an explicit remote host. This page is the shared config reference; the linked pages cover each backend's details, examples, and limits.

Configuration

security:
  sandbox:
    backend: auto                 # auto | bwrap | docker | ssh | none (default: none)
    network: none                 # none | bridge | host
    allowed_read_paths: []
    allowed_write_paths: []
    memory_limit: "256m"
    cpu_limit: 1.0
    read_only_rootfs: true
    bind_mounts: []
    env_passthrough: []
    docker:
      image: "python:3.12-slim"
      user: "auto"
      runtime: null               # null (runc) | runsc | kata-runtime | kata-qemu | kata-fc | kata-clh
      extra_args: []
    ssh:
      host: my-build-box          # required when backend: ssh
      remote_cwd: /srv/work       # optional; SSH login dir if unset
      identity_file: null         # optional override; falls back to ~/.ssh/config
      config_file: null           # optional override
      connect_timeout: 10
      control_persist: "60s"

backend

ValueBehavior
noneNo isolation. Tool subprocesses run on the host.
bwrapBubblewrap (Linux only). Lightweight user-namespace sandbox.
dockerDocker container. Requires a running Docker daemon.
sshRemote execution on a host via OpenSSH. Not a kernel sandbox. See SSH Backend.
autoPrefers bwrap on Linux, falls back to Docker. Never selects ssh (requires explicit host) and never falls to none.

network

Valuebwrapdocker
none--unshare-net (empty namespace)--network none
bridgeNot supported (raises error)--network bridge
hostHost network (no namespace)--network host

docker sub-config

  • image — Docker image (default python:3.12-slim).
  • user — Container user. "auto" maps to the current uid:gid when writable mounts exist. null runs as root.
  • runtime — Container runtime. null (default) uses Docker's default (runc). Other values: runsc (gVisor), kata-runtime, kata-qemu, kata-fc, kata-clh (Kata microVM hypervisor variants). Validated at preflight against the runtimes Docker has registered; an unregistered choice fails with a per-runtime install hint. Since v2026.5.2.
  • extra_args — Additional docker run flags. The schema blocks dangerous flags such as --privileged and --cap-add. --runtime is rejected here too; use runtime above instead.

ssh sub-config

  • host — required. Alias from ~/.ssh/config or user@hostname.
  • remote_cwd — working directory on the remote host. Defaults to the SSH login directory.
  • identity_file — optional IdentityFile override. Prefer setting this in ~/.ssh/config.
  • config_file — optional ~/.ssh/config path override.
  • connect_timeout — seconds for the initial connection (default 10).
  • control_persist — how long the multiplexed connection stays warm (default "60s", any OpenSSH duration string).

See SSH Backend for the full reference, the v1 limits (no bind_mounts, no python_exec yet), and the security posture warning.

For when to pick which backend, and what each runtime buys you, see Sandbox Comparison.

Backends at a glance

bubblewrapDockerSSH
PlatformLinux onlymacOS, Windows, LinuxAnywhere ssh is on PATH
DaemonNone (bwrap binary)Docker daemon requiredOpenSSH client; remote sshd
IsolationUser namespacesContainerNone (host-level on remote)
Startup costfork+execve~200–500ms per call~150–500ms cold, tens of ms warm (ControlMaster)
FilesystemHost /usr, /bin, /lib bound read-onlyPinned imageWhatever the remote host has
Network isolation--unshare-net--network noneNot enforced
Bridge networkingNot supported--network bridgeRejected at config load
Resource limitssystemd-run --user (skipped with a warning if unavailable)-m, --cpus, --pids-limitNone in v1
Bind mountsSupportedSupportedRejected at config load (v1)
Installapt install bubblewrapapt install docker.io or Docker Desktopapt install openssh-client

Mount validation

Mounts fall into two categories:

  • User-configured (allowed_read_paths, allowed_write_paths, bind_mounts from role YAML) — validated at load time against the role's permitted roots. A typo'd /etc mount fails before the role ever runs.
  • Tool-internal (e.g. python_exec writes code to /tmp and mounts it at /work/_run.py) — code-controlled, trusted, no validation.

Audit

Every sandboxed call logs a sandbox.exec security event:

FieldMeaning
backendwhich backend ran the command
argv0the command that ran
rcexit code
duration_mswall-clock time

Query with:

initrunner audit security-events --event-type sandbox.exec

Adaptive preflight

backend: auto and backend: bwrap run a functional probe before launching any tool:

bwrap --ro-bind /usr /usr -- /bin/true

If the probe fails, SandboxUnavailableError.remediation reads /proc/sys/kernel/unprivileged_userns_clone and /proc/sys/kernel/apparmor_restrict_unprivileged_userns and emits the specific fix — sysctl, AppArmor profile reinstall, or switch to backend: docker. The CLI renders the error as a clean Rich panel and exits with code 1.

initrunner doctor --role <file> now renders a sandbox row showing the resolved backend and readiness — Docker daemon reachable, bwrap probe passing, image pulled.

Migrating from security.docker

security.docker has been removed. A role still using it fails schema validation with migration instructions:

# Old (removed in v2026.4.16)
security:
  docker:
    enabled: true
    image: python:3.12-slim
    network: none

# New
security:
  sandbox:
    backend: docker
    network: none
    docker:
      image: python:3.12-slim

Bundle metadata

Published bundles declare supported_sandbox_backends in the manifest. initrunner install checks the host and warns when none of the listed backends is available. See OCI Distribution for the full manifest schema.

On this page