Sandboxing
WednesdayAI can run tools inside Docker containers to reduce blast radius. Sandboxing is optional and off by default; when it is off, tools run on the host with the same permissions as the gateway process. The gateway process itself always stays on the host — only tool execution moves into a container.
This is not a perfect security boundary, but it materially limits filesystem and process access when the model does something it should not.
When sandbox.mode is off (the default), tool code runs with the same permissions as the gateway process. Install only plugins you trust, and consider enabling a sandbox for non-main sessions.
What gets sandboxed
- Tool execution:
exec, read, write, edit, apply_patch, process, and similar.
- An optional sandboxed browser (
agents.defaults.sandbox.browser).
Not sandboxed:
- The gateway process itself.
- Any tool explicitly allowed to run on the host — in particular, elevated exec runs on the host and bypasses sandboxing.
Modes
agents.defaults.sandbox.mode controls when sandboxing is used:
| Mode | Effect |
|---|
off (default) | No sandboxing — tools run in the gateway process |
non-main | Sandboxes all sessions except the main session |
all | Every session runs in a sandbox |
non-main is based on session.mainKey (default "main"), not agent id. Group and channel sessions use their own keys, so they count as non-main and will be sandboxed in non-main mode — a common surprise.
Scope
agents.defaults.sandbox.scope controls how many containers are created:
| Scope | Effect |
|---|
session (default) | One container per session |
agent | One container per agent |
shared | One container shared by all sandboxed sessions |
Workspace access
agents.defaults.sandbox.workspaceAccess controls what the sandbox can see:
| Value | Effect |
|---|
none (default) | Tools see a fresh sandbox workspace under ~/.openclaw/sandboxes |
ro | Mounts the agent workspace read-only at /agent (disables write/edit/apply_patch) |
rw | Mounts the agent workspace read/write at /workspace |
Inbound media is copied into the active sandbox workspace (media/inbound/*). With workspaceAccess: "none", eligible skills are mirrored into the sandbox workspace so the (sandbox-rooted) read tool can see them.
Custom bind mounts
agents.defaults.sandbox.docker.binds mounts additional host directories. Format: host:container:mode, e.g. "/home/user/source:/source:ro". Global and per-agent binds are merged (under scope: "shared", per-agent binds are ignored).
{
agents: {
defaults: {
sandbox: {
docker: {
binds: ["/home/user/source:/source:ro", "/var/data/myapp:/data:ro"],
},
},
},
},
}
Binds bypass the sandbox filesystem and expose host paths with whatever mode you set. WednesdayAI blocks dangerous sources (docker.sock, /etc, /proc, /sys, /dev, and parent mounts that would expose them). Mount secrets and credentials :ro unless absolutely required — binding /var/run/docker.sock effectively hands host control to the sandbox.
Images and setup
The default image is openclaw-sandbox:bookworm-slim. Build it once:
The default image does not include Node. For a richer image with curl, jq, nodejs, python3, and git:
scripts/sandbox-common-setup.sh
# then set agents.defaults.sandbox.docker.image to openclaw-sandbox-common:bookworm-slim
For the sandboxed browser:
scripts/sandbox-browser-setup.sh
By default, sandbox containers run with no network (docker.network: "none"). Override with agents.defaults.sandbox.docker.network. network: "host" and network: "container:<id>" are blocked by default; the namespace-join break-glass override is agents.defaults.sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true.
openclaw doctor checks the sandbox image and offers to build or switch it when sandboxing is enabled but the image is missing.
Three related but distinct controls decide whether a tool runs and where:
- Sandbox (
agents.defaults.sandbox.*) decides where tools run — Docker vs host.
- Tool policy (
tools.*, tools.sandbox.tools.*, agents.list[].tools.*) decides which tools are available.
- Elevated (
tools.elevated.*) is an exec-only escape hatch to run on the host while sandboxed.
Rules of thumb:
- Tool policy is the hard stop.
deny always wins; if allow is non-empty, everything else is blocked.
- Tool policy applies before sandbox rules — sandboxing never re-enables a denied tool.
/exec only adjusts per-session exec defaults for authorized senders; it cannot override a denied exec tool.
- Elevated does not grant extra tools and does not override allow/deny.
/elevated on runs exec on the host (approvals may still apply); /elevated full skips exec approvals for the session.
Debugging “why is this blocked?”
openclaw sandbox explain
openclaw sandbox explain --session agent:main:main
openclaw sandbox explain --agent work
openclaw sandbox explain --json
It prints the effective sandbox mode, scope, and workspace access, whether the current session is sandboxed, the effective sandbox tool allow/deny (and where it came from), and the elevated gates with fix-it config keys.
Sandbox tool policy accepts group:* shorthands:
| Group | Expands to |
|---|
group:runtime | exec, bash, process |
group:fs | read, write, edit, apply_patch |
group:sessions | sessions_list, sessions_history, sessions_send, sessions_spawn, session_status |
group:memory | memory_search, memory_get |
group:ui | browser, canvas |
group:automation | cron, gateway |
group:messaging | message |
group:nodes | nodes |
group:openclaw | all built-in tools (excludes provider plugins) |
Minimal enable example
{
agents: {
defaults: {
sandbox: {
mode: "non-main",
scope: "session",
workspaceAccess: "none",
},
},
},
}
Related: Security hardening · Gateway configuration · Doctor