# Sandbox profiles

> OS-level isolation profiles (workspace, read-only, strict, devbox, off), --sandbox flag, custom deny globs, Linux vs macOS enforcement differences for child network.

- Repository: xai-org/grok-build
- GitHub: https://github.com/xai-org/grok-build
- Human docs: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458
- Complete Markdown: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458/llms-full.txt

## Source Files

- `crates/codegen/xai-grok-pager/docs/user-guide/18-sandbox.md`
- `crates/codegen/xai-grok-sandbox/src/profiles.rs`
- `crates/codegen/xai-grok-sandbox/src/lib.rs`
- `crates/codegen/xai-grok-sandbox/src/types.rs`
- `crates/codegen/xai-grok-sandbox/src/deny`
- `crates/codegen/xai-grok-pager/src/app/cli.rs`

---

---
title: "Sandbox profiles"
description: "OS-level isolation profiles (workspace, read-only, strict, devbox, off), --sandbox flag, custom deny globs, Linux vs macOS enforcement differences for child network."
---

Sandbox mode applies OS-level filesystem and network limits to the entire `grok` process at startup via the `xai-grok-sandbox` crate and the [nono](https://crates.io/crates/nono) kernel backend (Landlock on Linux, Seatbelt on macOS). Limits cover in-process tools (`read_file`, `search_replace`, `list_dir`) and child processes (`bash`, `rg`); they are irreversible once applied. Sandbox is **off** by default.

```bash
grok --sandbox workspace
grok --sandbox read-only
grok --sandbox strict
```

## Built-in profiles

| Profile | FS read | FS write | Child network | Typical use |
| --- | --- | --- | --- | --- |
| `off` (default) | Unrestricted | Unrestricted | Unrestricted | No sandbox |
| `workspace` | Everywhere | CWD + `~/.grok/` + `/tmp` + `/var/tmp` (+ macOS temp dirs / `$TMPDIR`) | Allowed | Everyday development |
| `devbox` | Everywhere | All top-level dirs except `/data` (skips `/proc`, `/sys`, `/dev`) | Allowed | Disposable dev VMs |
| `read-only` | Everywhere | `~/.grok/` + temp dirs only | Blocked on Linux¹ | Exploration, review |
| `strict` | CWD + essential system paths | CWD + `~/.grok/` + temp dirs | Blocked on Linux¹ | Untrusted code |

¹ Child-network blocking uses seccomp on **Linux only**. On macOS it is a no-op for these profiles.

Aliases accepted by the profile parser: `readonly` → `read-only`; `none` → `off`.

### Profile notes

- **workspace** — Recommended default when enabling the sandbox. Full filesystem read; writes limited to the workspace, Grok home (`$GROK_HOME` or `~/.grok`), and temp paths. Network allowed for in-process tools and child commands.
- **devbox** — Reserved built-in for disposable VMs. `--sandbox devbox` always selects the built-in profile and **shadows** any `[profiles.devbox]` in `sandbox.toml`. On Linux, `/data` is write-denied via a bubblewrap remount (still readable). `/data` is not put into the kernel read-deny set, so customs that `extends = "devbox"` do not inherit a read-deny on `/data`.
- **read-only** — Read everything; write only Grok home + temp (session persistence still works). Child network restricted on Linux.
- **strict** — No default full-FS read. Read allowlist includes CWD plus present system paths such as `/usr`, `/lib`, `/bin`, `/etc`, `/tmp`, `/run`, `/var`, and macOS paths like `/System`, `/Library`, `/private`, and `~/Library` when they exist. Child network restricted on Linux.

Device files needed for normal tools (`/dev/null`, `/dev/urandom`, `/dev/tty`, PTY paths, etc.) are granted separately by the capability set builder.

## Select a profile

### CLI and environment

| Input | Identifier | Notes |
| --- | --- | --- |
| Flag | `--sandbox <PROFILE>` | Profile name for this process |
| Env | `GROK_SANDBOX` | Same values as the flag |
| Config | `[sandbox] profile` in effective `config.toml` | User/project config merge |
| Requirements | `requirements.toml` → `[sandbox] profile` | Highest precedence pin |
| Default | `off` | No enforcement |

Profile resolution order for a **new** session:

1. Managed/requirements pin (`[sandbox] profile` in requirements)
2. Explicit `--sandbox` / `GROK_SANDBOX` (including the profile restored for resume)
3. `[sandbox] profile` in config
4. `off`

Related permission UX: `[sandbox] auto_allow_bash` and `GROK_SANDBOX_AUTO_ALLOW_BASH` can auto-approve bash when the sandbox is active (default false). That is orthogonal to OS enforcement; see [Permissions and safety](/permissions-and-safety).

### Config example

```toml
# ~/.grok/config.toml (or project .grok/config.toml via effective merge)
[sandbox]
profile = "workspace"
auto_allow_bash = false
```

## Custom profiles

Define named profiles in:

- Global: `~/.grok/sandbox.toml`
- Project: `<workspace>/.grok/sandbox.toml`

```toml
[profiles.project]
extends = "workspace"
restrict_network = true
read_only = ["/data"]
read_write = ["/tmp/scratch"]
deny = ["/data/shared-secrets", "**/.env", "**/*.pem"]
```

```bash
grok --sandbox project
```

### Fields

| Field | Type | Description |
| --- | --- | --- |
| `extends` | string | Base built-in: `workspace`, `devbox`, `read-only`, `strict`. Defaults to `workspace`. Cannot extend `off`/`none` or another custom profile |
| `restrict_network` | bool | Block network for child processes (Linux seccomp; no-op on macOS) |
| `read_only` | string[] | Extra read-only paths |
| `read_write` | string[] | Extra read-write paths |
| `deny` | string[] | Kernel-enforced read + write/rename deny paths or globs |

### Naming and merge rules

- A custom name cannot replace a built-in. `--sandbox devbox` always runs the built-in `devbox`.
- Global and project files: project config may **add** new profile names only. If the same custom name exists globally, the **user/global definition wins**; the project entry is ignored (prevents a workspace from emptying a trusted `deny` list).
- When both define the same name with **different** content, Grok warns at startup (TUI welcome screen, or stderr in headless). Identical duplicates do not warn.

## Deny paths and globs

A non-empty custom `deny` list is **kernel-enforced**: denied paths cannot be read (via tools, `bash`, `grep`, or subagents) and cannot be renamed/relocated out of the deny set (`mv secret x && cat x` is closed).

- Entry is a **glob** if it contains `*`, `?`, or `[`. Those characters always mean glob.
- Supported gitignore-style subset: `*`, `?`, `**` as a whole segment, `[abc]` / `[a-z]`, negation with `!` or `^`.
- **Not** supported: brace alternation `{a,b}`, backslash escapes, unusual class forms. Unsupported or malformed globs cause Grok to **refuse to start** on both platforms.
- Relative globs are anchored at the workspace; absolute globs use their literal prefix. Non-glob entries use exact-path matching.

### Platform enforcement

| Platform | Mechanism | Glob behavior |
| --- | --- | --- |
| **macOS** | Seatbelt rules (read-deny + write sub-actions; `/private` firmlink aliases covered) | Globs become runtime regexes — files created **after** start still match |
| **Linux** | bubblewrap bind-over with mode-000 placeholders for read-deny; Landlock for allow grants | Globs expanded to files that **exist at launch** only; later matches are **not** covered |

On Linux, if bubblewrap is missing (or a deny path cannot be bound, or glob expansion exceeds caps — depth 64, 4096 matches, 200k entries walked), a profile that **requires** read-deny **refuses to start**. Built-in `devbox` (write-deny `/data` only) may fall back to Landlock with a warning when bwrap is unavailable.

## How enforcement works

```text
  Startup
     │
     ├─ resolve profile (requirements > CLI/env/resume > config > off)
     ├─ Linux: optional bwrap re-exec for deny /devbox /data
     └─ SandboxManager::apply → install (OnceLock, irreversible)
              │
              ├─ Landlock / Seatbelt CapabilitySet (FS)
              └─ RESTRICT_CHILD_NETWORK flag → seccomp in child pre_exec (Linux)
```

- Applied to the **whole process**, not per-command wrappers.
- Child FS restrictions inherit from the parent kernel policy.
- In-process HTTP (`web_search`, LLM API) is never blocked by child-network rules; the agent process needs network to function.
- On Linux with `restrict_network`: child commands such as `curl`, `wget`, and `npm install` fail with EPERM via seccomp (blocked syscalls include `connect`, `bind`, `sendto`, `sendmsg`, `listen`, `accept`, `accept4`).

If the platform cannot apply a **built-in** profile, Grok logs a warning and continues without enforcement. An explicitly requested **custom** profile that cannot be applied is fail-closed: process exit rather than run unsandboxed.

## Sessions and resume

The profile is stored with the session and is fixed for that session’s lifetime.

| Resume action | Result |
| --- | --- |
| Omit `--sandbox` | Restore saved profile |
| `--sandbox` matches saved | Allowed |
| `--sandbox` differs from saved | Error exit — start a new session to change profile |

Error shape (conceptually): cannot resume under profile `X` when the session was created with `Y`.

## Event logging

Events append to `~/.grok/sandbox-events.jsonl` (under Grok home), including:

- Profile applied (profile, workspace, platform, path sets, `restrict_network`)
- Apply failed
- Filesystem / network violations (when logged by tools)

## When to use which profile

| Situation | Profile / approach |
| --- | --- |
| Own project, basic write protection | `workspace` |
| Block `.env` / credentials on top of a base | Custom profile + `deny` |
| Review without writing project files | `read-only` |
| Untrusted third-party tree | `strict` |
| Disposable VM with broad writes but not `/data` | `devbox` |
| Need `npm install` / writes outside CWD / max flexibility | `off` |

Sandbox is one layer beside permission rules, hooks, and modes. OS isolation does not replace deny rules or `PreToolUse` hooks; combine them for defense in depth.

## Platform support

| Platform | Mechanism | Notes |
| --- | --- | --- |
| Linux | Landlock (+ bwrap for read-deny / devbox `/data`) | Kernel 5.13+ for Landlock; bubblewrap required for custom `deny` read-deny |
| macOS | Seatbelt | All versions; child network restrict is no-op |
| Windows / non-enforce builds | Not applied | Built without `enforce` or non-Unix: helpers compile; no kernel isolation |

## Related pages

<CardGroup>
  <Card title="Permissions and safety" href="/permissions-and-safety">
    Tool authorization pipeline, permission modes, and how sandbox interacts with allow/deny/ask rules.
  </Card>
  <Card title="Configure Grok" href="/configure-grok">
    Config precedence, feature flags, and inspecting resolved settings.
  </Card>
  <Card title="Configuration reference" href="/configuration-reference">
    Schema for `[sandbox]` and related keys in config.toml.
  </Card>
  <Card title="Headless mode" href="/headless-mode">
    Non-interactive runs where sandbox and tool allow/deny lists matter for CI.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Shared runtime flags including `--sandbox` / `GROK_SANDBOX`.
  </Card>
</CardGroup>
