Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion content/manuals/ai/sandboxes/security/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ and ICMP are blocked at the network layer.

## Isolation layers

The sandbox security model has four layers. See
The sandbox security model has five layers. See
[Isolation layers](isolation/) for technical details on each.

- **Hypervisor isolation:** separate kernel per sandbox. No shared memory or
Expand All @@ -52,6 +52,9 @@ The sandbox security model has four layers. See
[Deny-by-default policy](defaults/). Non-HTTP protocols blocked entirely.
- **Docker Engine isolation:** each sandbox has its own Docker Engine with no
path to the host daemon.
- **Source-repository isolation (clone mode):** the agent works on a private
in-VM clone with your `.git` mounted read-only. Even an unconstrained
agent cannot corrupt your host repository.
- **Credential isolation:** API keys are injected into HTTP headers by the
host-side proxy. Credential values never enter the VM.

Expand Down
68 changes: 64 additions & 4 deletions content/manuals/ai/sandboxes/security/isolation.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
---
title: Isolation layers
weight: 10
description: How Docker Sandboxes isolate AI agents using hypervisor, network, Docker Engine, and credential boundaries.
keywords: docker sandboxes, isolation, hypervisor, network, credentials
description: How Docker Sandboxes isolate AI agents using hypervisor, network, Docker Engine, source-repository, and credential boundaries.
keywords: docker sandboxes, isolation, hypervisor, network, credentials, git
---

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

AI coding agents need to execute code, install packages, and run tools on
your behalf. Docker Sandboxes run each agent in its own microVM with four
isolation layers: hypervisor, network, Docker Engine, and credential proxy.
your behalf. Docker Sandboxes run each agent in its own microVM with five
isolation layers: hypervisor, network, Docker Engine, source-repository
(in clone mode), and credential proxy.

## Hypervisor isolation

Expand Down Expand Up @@ -73,6 +74,65 @@ Host system
└── [VM] Containers created by agent
```

## Source-repository isolation

When you start a sandbox with `--clone` (see the
[clone-mode workflow](../usage.md#clone-mode)), the agent never works
directly against your host repository. Even with full root inside the VM,
it cannot corrupt your local Git state.

The boundary works like this:

- Your repository's Git root is bind-mounted into the sandbox at
`/run/sandbox/source` as a read-only mount. The agent — and anything it
spawns — cannot write to your `.git` directory, your working tree, or
any tracked file via that mount.
- The agent's working copy is a private `git clone --reference` populated
on the sandbox's overlay filesystem. The clone has its own index, its
own refs, and its own working tree. Object storage is shared via
`.git/objects/info/alternates`, so the clone is space-efficient and
full history is walkable, but writes to the clone never reach your
host's object database.
- Your host pulls the agent's commits over a `git-daemon` exposed by the
sandbox on `127.0.0.1:<ephemeral-port>`. The CLI registers it as a
`sandbox-<sandbox-name>` remote on your host repository. Fetching from
that remote uses the same trust model as fetching from any third-party
remote: nothing is integrated until you explicitly merge or check out
the fetched refs.

```plaintext
Host repository Sandbox VM
.git/ /run/sandbox/source/ (RO bind mount)
objects/ ◄─────── alternates ───────── clone/.git/objects/
refs/ clone/.git/refs/ (private)
HEAD clone/.git/HEAD (private)
working tree clone/working tree (overlay FS)
remote sandbox-<name> ──── git:// ────► git-daemon :9418
(published 127.0.0.1:<ephemeral>)
```

The practical guarantees:

- Index and ref corruption can't happen — concurrent `git` commands on the
host and inside the sandbox don't race on a shared `.git/index` or shared
refs because there is no shared writable state.
- The agent can't write back to your working tree. A compromised or buggy
agent can't drop a `.git/hooks/pre-commit`, modify `.github/workflows/`,
or edit any other tracked file in a way that affects your host until you
fetch and merge from the `sandbox-<name>` remote.
- Credentials, signing keys, and global settings declared in your
repository's `.git/config` stay on the host. The agent's clone has its
own independent configuration.
- Cleanup is automatic: `sbx rm` deletes the clone, the published port,
and the `sandbox-<name>` remote on your host. Any in-container commits
that have not been fetched or pushed to an upstream remote are dropped
with the sandbox — `sbx rm` prints a warning before doing so.

In direct mode (no `--clone`), the agent edits your working tree directly
and this isolation does not apply. Use clone mode whenever you want a
strong boundary between the agent's Git activity and your host
repository.

## Credential isolation

Most agents need API keys for their model provider. Rather than passing keys
Expand Down
21 changes: 15 additions & 6 deletions content/manuals/ai/sandboxes/security/workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ includes:
> building, or opening the project in an IDE. Review these files after any agent
> session before performing those actions.

## Branch mode
## Clone mode

The `--branch` flag lets the agent work on a separate branch. This is a
workflow convenience, not a security boundary: the agent still mounts the full
repository. See the [usage guide](../usage.md) for details.
The `--clone` flag isolates the agent from your host repository: it works
on a private clone inside the sandbox, with your `.git` directory
bind-mounted as a read-only reference. This means the agent cannot modify
any tracked file or any byte under `.git/` on your host, no matter how
unconstrained the agent runs. You see the agent's commits only after
explicitly running `git fetch sandbox-<name>`.

See [Source-repository isolation](isolation.md#source-repository-isolation)
for the full boundary, and the [usage guide](../usage.md#clone-mode) for
the workflow.

## Reviewing changes

Expand All @@ -52,10 +59,12 @@ With the default direct mount, changes are in your working tree:
$ git diff
```

If you used `--branch`, the agent's changes are on a separate branch:
If you used `--clone`, the agent's changes are on the `sandbox-<name>`
remote until you fetch and merge them:

```console
$ git diff main..my-feature
$ git fetch sandbox-my-sandbox
$ git diff main..sandbox-my-sandbox/<branch-the-agent-used>
```

Pay particular attention to:
Expand Down
174 changes: 94 additions & 80 deletions content/manuals/ai/sandboxes/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,117 +79,131 @@ When your workspace is a Git repository, the agent edits your working tree
directly by default. Changes appear in your working tree immediately, the same
as working in a normal terminal.

If you run multiple agents on the same repository at once, use [branch
mode](#branch-mode) to give each agent its own branch and working directory.
If you want the agent to work in isolation from your host repository — for
example to run multiple agents in parallel, or to prevent any chance of an
agent rewriting your local Git state — use [clone mode](#clone-mode). The
agent runs against a private Git clone inside the sandbox; your host repository
sees the agent's commits only after you explicitly fetch them.

### Direct mode (default)

The agent edits your working tree directly. Stage, commit, and push as you
normally would. If you run multiple agents on the same repository at the same
time, they may step on each other's changes. See
[branch mode](#branch-mode) for an alternative.

### Branch mode

Pass `--branch <name>` to give the agent its own
[Git worktree](https://git-scm.com/docs/git-worktree) and branch. This
prevents conflicts when multiple agents, or you and an agent, write to the
same files at the same time. You can set `--branch` on `create`, `run`, or
both.

The CLI creates worktrees under `.sbx/` in your repository root. The
worktree is a separate working directory, so the agent doesn't touch your main
working tree. This means:

- The worktree branches off your latest commit when you create it.
Uncommitted changes in your working tree are not included (`sbx` warns you
if it detects any).
- Files you add or change in your main working tree won't be visible to the
agent, and vice versa. The two directories are independent.

#### Starting a branch
[clone mode](#clone-mode) for an alternative.

### Clone mode

Pass `--clone` to run the agent on a private Git clone living entirely
inside the sandbox, instead of bind-mounting your working tree. Your host
repository is mounted read-only as the clone's reference, so the agent — even
with full root inside the VM — cannot modify any byte of your `.git`
directory or working tree. You can set `--clone` on `create` or, equivalently,
on `run` at create time.

When `--clone` is active:

- The agent works on a private clone populated by
`git clone --reference` from your repository, on the sandbox's overlay
filesystem. The clone has its own index, refs, and working tree.
Object storage is shared via `.git/objects/info/alternates`, so the
clone is space-efficient and full history is walkable, but writes to
the clone never reach your host's object database.
- Your repository's Git root is bind-mounted at `/run/sandbox/source` as a
read-only mount. The agent's `git clone --reference` reads from this
mount; nothing on the host is writable from inside the sandbox.
- The clone follows whatever HEAD your host repository is on at create time.
No branch is created automatically — if you want the agent to work on a
dedicated branch, instruct the agent to `git checkout -b my-feature`
inside the sandbox before it starts editing.
- The sandbox runs a `git-daemon` over a `127.0.0.1`-bound ephemeral port
that exports the in-container clone. The CLI registers it as a Git remote
named `sandbox-<sandbox-name>` on your host repository, so you can pull
the agent's commits with `git fetch`.
- Forge remotes you have on the host (`origin`, `upstream`, …) are
propagated into the in-container clone with their existing URLs, so the
agent can `git push origin …` to your GitHub fork as you would on the
host. Local-path remotes (`file://`, paths) are skipped because they
aren't reachable from inside the sandbox.

See [Source-repository isolation](security/isolation.md#source-repository-isolation)
for the security boundary.

#### Starting a sandbox in clone mode

```console
$ sbx run claude --branch my-feature # agent works on the my-feature branch
$ sbx run --clone claude # private clone of the current repository
```

Use `--branch auto` to let the CLI generate a branch name for you:
You can also create the sandbox first and attach later:

```console
$ sbx run claude --branch auto
$ sbx create --clone --name my-sandbox claude .
$ sbx run my-sandbox # resumes in the in-container clone
```

You can also create the sandbox first and add a branch at run time:
> [!NOTE]
> Clone mode is fixed at create time. Recreate the sandbox with
> `sbx create --clone ...` to switch an existing sandbox into clone mode.

```console
$ sbx create --name my-sandbox claude .
$ sbx run --branch my-feature my-sandbox
```

Or set the branch at create time and reuse it on subsequent runs:

```console
$ sbx create --name my-sandbox --branch my-feature claude .
$ sbx run my-sandbox # resumes in the my-feature worktree
$ sbx run --branch my-feature my-sandbox # same — reuses the existing worktree
```

#### Multiple branches per sandbox
#### Reviewing and pushing changes

You can run multiple worktrees in the same sandbox by passing different branch
names:
The CLI wires the agent's in-container clone as a `sandbox-<sandbox-name>`
Git remote on your host repository. Review the agent's work with the same
commands you'd use for any other remote — no extra tooling, no `cd` into
a separate directory:

```console
$ sbx run --branch feature-a my-sandbox
$ sbx run --branch feature-b my-sandbox
$ git fetch sandbox-my-sandbox # pull the agent's commits
$ git log sandbox-my-sandbox/<branch-the-agent-used> # see what the agent did
$ git diff main..sandbox-my-sandbox/<branch-the-agent-used>
$ git checkout -b my-feature sandbox-my-sandbox/<branch-the-agent-used>
$ git push -u origin my-feature
$ gh pr create
```

#### Reviewing and pushing changes
If the agent committed on a dedicated branch (because you asked it to
`git checkout -b ...`), that branch name appears on the `sandbox-<name>`
remote. If it stayed on the HEAD it inherited at create time, its commits
extend that branch instead — you'll see them by fetching and diffing.

To review the agent's work, find the worktree with `git worktree list`, then
push or open a PR from there:
Some agents don't commit automatically. If `git log sandbox-<name>/...`
shows nothing new, open a shell in the sandbox and commit from there
before fetching. `sbx exec` drops you into the in-container clone:

```console
$ git worktree list # find the worktree path
$ cd .sbx/<sandbox-name>-worktrees/my-feature
$ git log # see what the agent did
$ git push -u origin my-feature
$ gh pr create
$ sbx exec -it my-sandbox bash
$ git commit -am "save work"
```

Some agents don't commit automatically and leave changes uncommitted in the
worktree. If that happens, commit from the worktree directory before pushing.

See [Workspace trust](security/workspace.md) for security considerations when
reviewing agent changes.

#### Cleanup

`sbx rm` removes the sandbox and all of its worktrees and branches.

#### Ignoring the `.sbx/` directory
`sbx rm` deletes the sandbox, its in-container clone, the published Git
port, and the `sandbox-<sandbox-name>` remote on your host repository.

Branch mode stores worktrees under `.sbx/` in your repository root. To keep
this directory out of `git status`, add it to your project's `.gitignore`:
> [!WARNING]
> Any commits the agent made inside the sandbox that you have not yet
> fetched (via `git fetch sandbox-<name>`) or pushed to an upstream
> remote will be lost — the in-container clone lives on the sandbox's
> overlay filesystem and is dropped with it. `sbx rm` prints a warning
> for clone-mode sandboxes; review it before confirming the removal.

```console
$ echo '.sbx/' >> .gitignore
```

Or, to ignore it across all repositories, add `.sbx/` to your global gitignore:

```console
$ echo '.sbx/' >> "$(git config --global core.excludesFile)"
```
#### Restrictions

> [!TIP]
> If `git config --global core.excludesFile` is empty, set one first:
> `git config --global core.excludesFile ~/.gitignore`.
A few configurations are incompatible with clone mode and are rejected at
create time:

You can also create Git worktrees yourself and run an agent directly in one,
but the sandbox won't have access to the `.git` directory in the parent
repository. This means the agent can't commit, push, or use Git. `--branch`
solves this by setting up the worktree so that Git works inside the sandbox.
- `--clone` together with `--workspace-volume`: the source-repository
isolation relies on bind-mounting your Git root, which is incompatible
with a volume-backed workspace.
- `--clone` from inside a host Git worktree: the bind mount can't resolve
the worktree's `.git` pointer file. Run `sbx create --clone ...` from
the main repository instead.
- `--clone` on a non-Git workspace: clone mode requires a Git repository.
Run `sbx create` without `--clone` for non-Git workspaces.

### Signed commits

Expand Down Expand Up @@ -253,7 +267,7 @@ $ sbx create claude .
```

Unlike `run`, `create` requires an explicit workspace path. It uses direct
mode by default, or pass `--branch` for [branch mode](#branch-mode). Attach
mode by default, or pass `--clone` for [clone mode](#clone-mode). Attach
later with `sbx run`:

```console
Expand All @@ -264,8 +278,8 @@ $ sbx run claude-my-project

You can mount extra directories into a sandbox alongside the main workspace.
The first path is the primary workspace — the agent starts here, and the
sandbox's Git worktree is created from this directory if you use `--branch`.
Extra workspaces are always mounted directly.
sandbox's in-container Git clone is populated from this directory if you
use `--clone`. Extra workspaces are always mounted directly.

All workspaces appear inside the sandbox at their absolute host paths. Append
`:ro` to mount an extra workspace read-only — useful for reference material or
Expand Down