> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wednesdayai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandboxing

> Run agent tools inside Docker containers to limit blast radius — modes, scope, workspace access, and how sandbox interacts with tool policy and elevated exec.

# 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.

<Warning>
  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.
</Warning>

## 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                  |

<Note>
  `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.
</Note>

## 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).

```json5 theme={"dark"}
{
  agents: {
    defaults: {
      sandbox: {
        docker: {
          binds: ["/home/user/source:/source:ro", "/var/data/myapp:/data:ro"],
        },
      },
    },
  },
}
```

<Warning>
  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.
</Warning>

## Images and setup

The default image is `openclaw-sandbox:bookworm-slim`. Build it once:

```bash theme={"dark"}
scripts/sandbox-setup.sh
```

The default image does **not** include Node. For a richer image with `curl`, `jq`, `nodejs`, `python3`, and `git`:

```bash theme={"dark"}
scripts/sandbox-common-setup.sh
# then set agents.defaults.sandbox.docker.image to openclaw-sandbox-common:bookworm-slim
```

For the sandboxed browser:

```bash theme={"dark"}
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.

## Sandbox vs tool policy vs elevated

Three related but distinct controls decide whether a tool runs and where:

1. **Sandbox** (`agents.defaults.sandbox.*`) decides **where** tools run — Docker vs host.
2. **Tool policy** (`tools.*`, `tools.sandbox.tools.*`, `agents.list[].tools.*`) decides **which** tools are available.
3. **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?"

```bash theme={"dark"}
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.

### Tool groups

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

```json5 theme={"dark"}
{
  agents: {
    defaults: {
      sandbox: {
        mode: "non-main",
        scope: "session",
        workspaceAccess: "none",
      },
    },
  },
}
```

***

**Related:** [Security hardening](/admin/security) · [Gateway configuration](/admin/gateway/configuration) · [Doctor](/admin/doctor)
