OpenClaw sandbox: modes, Docker, Podman and exec approvals
Off by default, so exec runs on the host. Sandbox modes, the Docker, Podman, SSH, OpenShell and Crabbox backends, what a sandbox can reach, and exec approvals.
OpenClaw’s sandbox runs an agent’s tools, its shell commands and file reads and writes, in a container or on another machine while the gateway itself stays on the host. It is off by default: out of the box, exec runs commands on the gateway’s own machine with no approval prompts. Set agents.defaults.sandbox.mode to non-main to sandbox every session except your own main chat, or to all for every session. Docker is the default backend, with no network and a read-only root; as of OpenClaw 2026.9.7, Podman, SSH, OpenShell and Crabbox are the others. Exec approvals and tool policy are separate walls: approvals decide which commands may run on the host, and tool policy removes tools altogether.
The default: no sandbox, no prompts
OpenClaw assumes one trust boundary per gateway: a single operator, or a team whose members trust each other. Its trust model calls host exec without approval prompts the “trusted single-operator default”, and the same page spells out what the agent can then do: “execute arbitrary shell commands, read/write files, access network services, and send messages to anyone (if given channel access).” Most failures, it says, are not exotic exploits but “someone messaged the bot and the bot did what they asked.”
Three controls change that, and OpenClaw’s docs keep them apart: the sandbox decides where tools run, tool policy decides which tools exist, and elevated mode is an exec-only way back out of the sandbox. Exec approvals sit beside them and decide which commands may run on a real host. When something is blocked, or runs when it should not, ask OpenClaw which control applies:
openclaw sandbox explain --agent <agent-id>
openclaw sandbox explain --session <session-key>CopiedIt prints the effective sandbox mode and workspace access, the sandbox tool policy, the elevated gates and the config keys to change.
Do you need the sandbox?
It earns its place when something other than you can steer a session that has tools. Group chats and channels are the clearest case: they get session keys of their own, so non-main sandboxes them while your own chat with the agent runs as before. Untrusted content is the other: a web page, an email or a pasted log can carry instructions even when only you can message the agent, and OpenClaw’s prompt-injection guidance says to run sensitive tool execution in a sandbox, and to sandbox every session for an agent on a smaller model.
What it costs: a backend that answers, an image built in advance, and sandboxed sessions that start with no network and a shorter tool list (both below). Under non-main, isolated cron runs, webhook runs and sub-agents are non-main too, so they move into the sandbox along with the group chats. The default, with no sandbox, is the setup OpenClaw builds for one person talking to their own agent.
Turn it on: mode and scope
Three settings decide it (modes, scope and backend). The mode says which sessions are sandboxed:
off, the default: none, unless a role requires it (below).non-main: every session except the agent’s main one,agent:<id>:main.all: every session, the main chat included.
The scope says how many sandboxes there are: agent, the default, gives each agent one sandbox shared by all its sandboxed sessions; session gives each session its own; shared puts every sandboxed session in one.
openclaw config set agents.defaults.sandbox.mode non-main
openclaw config set agents.defaults.sandbox.scope sessionCopiedAn agent’s own sandbox block overrides the global one, so a family or group agent can run sandboxed beside a personal agent that is not. A named operator role whose sandbox policy is required sandboxes the sessions it creates whatever the mode says, and if the backend is unavailable those sessions fail closed instead of running on the host. A sandbox that is already running can keep its old settings until it is recreated; openclaw sandbox recreate --all removes every sandbox, and the next use creates each one from the current config.
Pick a backend
agents.defaults.sandbox.backend chooses where sandboxed tools run. As of 2026.9.7 there are five (what each supports):
docker, the default: local containers through thedockercommand, which has to reach a Docker daemon as the user the gateway runs as. It is the only backend with a sandboxed browser.podman: the native Podman command, built in, and it never falls back to Docker. The sandbox image has to be in Podman’s own store, and the engine host needscatatonitfor the container’s init process (Podman backend). No sandboxed browser. Running the gateway itself in Podman is a separate setup.ssh: any machine reachable over SSH that has/bin/sh,python3and GNUstatandreadlink. The workspace is copied there once and the remote copy becomes the real one: nothing syncs back. No sandboxed browser, and the network is whatever that machine allows (SSH backend).openshell: a plugin backend for sandboxes managed by OpenShell, which needs theopenshellcommand and a reachable OpenShell gateway. Its defaultmirrormode copies the workspace in before each command and back after;remotemode works like SSH. No sandboxed browser yet (OpenShell backend).crabbox: a throwaway cloud machine leased through Crabbox, with Daytona leases supported first. The docs warn that “every tool call crosses the network, so expect higher latency than Docker” (Crabbox backend). Its docs arrived with 2026.9.5, and the 2026.8 extended-stable line documents only the other four.
On Docker, a sandboxed session that cannot reach the daemon stops before the model is called rather than running on the host. That is the “Sandbox mode requires Docker” error, which has a guide of its own.
Setting up the Docker backend
Docker has to answer the user the gateway runs as, not only you. Run this as that user; a version number means OpenClaw will reach Docker too:
docker version --format '{{.Server.Version}}'CopiedThen build the image. OpenClaw does not pull it or substitute plain Debian, so the first sandboxed run on a fresh machine stops with “Sandbox image not found: openclaw-sandbox:bookworm-slim”. From a source checkout, scripts/sandbox-setup.sh builds it. The npm package leaves that script out, and the images page gives the build inline:
docker build -t openclaw-sandbox:bookworm-slim - <<'DOCKERFILE'
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bash ca-certificates curl git jq python3 ripgrep \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --shell /bin/bash sandbox
USER sandbox
WORKDIR /home/sandbox
CMD ["sleep", "infinity"]
DOCKERFILECopiedThat image carries bash, curl, git, jq, python3 and ripgrep, and no Node. The same page builds a larger openclaw-sandbox-common image with Node 24 and pnpm for agents that need them.
What a sandboxed session can reach
Files. workspaceAccess decides how much of the agent’s own workspace the sandbox sees (workspace access):
none, the default: tools work in a separate sandbox workspace under~/.openclaw/sandboxes, and the agent’s workspace is not visible.ro: the agent’s workspace is mounted read-only at/agent, and the write, edit and patch tools are off.rw: the agent’s workspace is mounted read-write at/workspace.
openclaw config set agents.defaults.sandbox.workspaceAccess roCopiedOn SSH and OpenShell, shell commands are held only by what the remote host or the OpenShell policy enforces: workspaceAccess alone does not make remote paths read-only.
The container. Docker and Podman sandboxes start with no network, a read-only root filesystem, every Linux capability dropped and no-new-privileges (Docker backend). Installing system packages from inside a turn is meant to fail; they belong in a custom image. For outbound access, set the network to bridge; host is refused.
openclaw config set agents.defaults.sandbox.docker.network bridgeCopiedThe tools. Sandboxed sessions also get a tool list of their own. In OpenClaw’s source at 2026.9.7, the default allows exec, process, the file tools, view_image and the session and sub-agent tools, and denies the browser, canvas, nodes, the scheduler, the gateway tool and channel-specific tools. Because that allow list is not empty, every other tool is unavailable too, web search and fetch, memory search and plugin and MCP tools included. Add what a sandboxed session needs:
openclaw config set tools.sandbox.tools.alsoAllow \
'["web_search","web_fetch"]' --strict-jsonCopiedWhen the sandbox policy blocks a call, the gateway log (openclaw logs) records an agents/tool-policy entry naming the rule.
Two things stay outside the sandbox whatever the backend: the gateway itself, along with plugin and MCP tools, which run on the gateway’s side even for a sandboxed session once the sandbox tool policy allows them; and commands sent through elevated mode (below).
Exec approvals: which commands run on the host
tools.exec.mode sets the policy for commands that run on a real host, the gateway’s machine or a paired node (permission modes):
full, the default on gateway and node: no ordinary prompts.ask: allowlisted commands run, anything else waits for a person.auto: allowlisted commands run; for the rest a model, the agent’s own unless you set another, answers allow (once), deny (with a reason the agent sees) or ask a person. Three denials in a row in one session go to a person.allowlist: allowlisted commands run, and the rest are refused without asking.deny: no host exec.
openclaw config set tools.exec.mode ask
openclaw approvals get
openclaw gateway restartCopiedThe host keeps an approvals file of its own, and the stricter of it and the config wins: tightening the config is enough, loosening needs both. openclaw approvals get shows the requested policy, where each part comes from and the result (exec approvals). Older configs set tools.exec.security and tools.exec.ask instead; openclaw doctor --fix converts each pair that has an equivalent mode, and a config patch that mixes both styles is rejected.
Approvals bind only commands on a real host. Inside a sandbox, exec runs without them: in the exec tool’s source at 2026.9.7, the approvals file and the allowlist check are consulted only for the gateway and nodes. In a sandboxed session, the sandbox is the wall.
Prompts appear in the Control UI and the companion apps, and Discord, Slack, Telegram, Matrix and QQ can show them as approval cards in the chat. A prompt nobody can answer falls back to deny. Scheduled jobs are stricter: their prompts go only to a connected Control UI or app, never to a chat, and with nothing connected they are denied at once. So an agent on ask with nobody there to answer runs only what its allowlist already covers.
Allowlists are kept per agent and edited in the Control UI under Nodes, Exec approvals. If one includes an interpreter such as python or node, turn on tools.exec.strictInlineEval; otherwise python -c "..." runs on the interpreter’s approval.
The Control UI’s chat composer also has an Execution permissions menu that sets a policy for one session (session permission modes): read-only (reads, no exec), guarded (reads and writes inside the session’s folder, normally the agent’s workspace, with a person approving commands the allowlist misses), workspace (the same folder limit, with the model reviewer first) or full. Left on Default, a session follows the config, which with nothing set and no sandbox means full access.
Tool policy: the hard stop
Every tool passes an allow/deny check before the model sees it. tools.deny removes tools or whole groups: tools.deny: ["group:runtime"] takes away exec, process and code_execution together. Deny always wins, a non-empty allow list blocks everything not on it, and nothing downstream brings a denied tool back: not the sandbox, not /exec, not elevated mode. Each agent can carry its own lists in its own tools block. Disabling the file tools does not make exec read-only, since a shell can write files; an agent that must not change anything has to lose exec too.
Elevated mode: the gated way out of the sandbox
Elevated mode lets a sandboxed session run exec on the host: the gateway, or a paired node when that is the configured exec target. In a session that is not sandboxed it changes nothing, since exec already runs on the host. It needs two gates: tools.elevated.enabled set to true, and the sender listed for that channel under tools.elevated.allowFrom. Then, in the chat:
/elevated on: commands leave the sandbox, and approvals still apply./elevated full: commands leave the sandbox and skip approvals when the exec policy is alreadyfull./elevated off: back to the sandbox.
It cannot run a tool that tool policy denies, and it cannot leave a sandbox that a role requires.
What this buys you against prompt injection
On prompt injection, OpenClaw’s own page now treats model choice as the first and cheapest layer. It cites a 2026 arena of 272,000 attacks, counted only when the agent both carried out the harmful action and hid it from the user, where attacks worked 0.5% of the time against Claude Opus 4.5 and 8.5% against Gemini 2.5 Pro. It adds that published success rates pass 80% against state-of-the-art defenses once attackers adapt, and that smaller or older models are markedly easier to steer. So the hard walls stay: pairing and channel allowlists on who can talk to the agent, and tool policy, approvals and the sandbox on what a fooled turn can reach. For untrusted content, the same page suggests a read-only or tool-less reader agent that summarizes it for your main agent.
The outermost wall is the machine: an agent on a computer that isn’t your daily driver keeps your own files, browser sessions and passwords off the machine a hijacked turn can reach. Once the layers are chosen, the built-in security audit checks how the config landed. Among its checks are Docker sandbox settings present while sandboxing is off, bind mounts onto credential or Docker socket paths, a host network mode, and file tools denied while exec stays on.