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

# Agent approvals & security

ZeroCode helps protect your code and data and reduces the risk of misuse.

This page covers how to operate ZeroCode safely, including sandboxing, approvals,
and network access. If you are looking for ZeroCode Security, the product for
scanning connected GitHub repositories, see [ZeroCode Security](/permissions).

By default, the agent runs with network access turned off. Locally, ZeroCode uses an OS-enforced sandbox that limits what it can touch (typically to the current workspace), plus an approval policy that controls when it must stop and ask you before acting.

For a high-level explanation of how sandboxing works across the ZeroTwo desktop app,
ZeroTwo desktop app, and desktop app, see [sandboxing](/sandboxing).
For a broader enterprise security overview, see the [ZeroCode security white paper](https://trust.zerotwo.ai/?itemUid=382f924d-54f3-43a8-a9df-c39e6c959958\&source=click).

## Sandbox and approvals

ZeroCode security controls come from two layers that work together:

* **Sandbox mode**: What ZeroCode can do technically (for example, where it can write and whether it can reach the network) when it executes model-generated commands.
* **Approval policy**: When ZeroCode must ask you before it executes an action (for example, leaving the sandbox, using the network, or running commands outside a trusted set).

ZeroCode uses different sandbox modes depending on where you run it:

* **ZeroCode cloud**: Runs in isolated ZeroTwo-managed containers, preventing access to your host system or unrelated data. Uses a two-phase runtime model: setup runs before the agent phase and can access the network to install specified dependencies, then the agent phase runs offline by default unless you enable internet access for that environment. Secrets configured for cloud environments are available only during setup and are removed before the agent phase starts.
* **ZeroTwo desktop app / desktop app**: OS-level mechanisms enforce sandbox policies. Defaults include no network access and write permissions limited to the active workspace. You can configure the sandbox, approval policy, and network settings based on your risk tolerance.

In the `Auto` preset (for example, `--sandbox workspace-write --ask-for-approval on-request`), ZeroCode can read files, make edits, and run commands in the working directory automatically.

ZeroCode asks for approval to edit files outside the workspace or to run commands that require network access. If you want to chat or plan without making changes, switch to `read-only` mode with the `/permissions` command.

ZeroCode can also elicit approval for app (connector) tool calls that advertise side effects, even when the action isn't a shell command or file change. Destructive app/MCP tool calls always require approval when the tool advertises a destructive annotation, even if it also advertises other hints (for example, read-only hints).

## Network access ⚠️ **Elevated risk**

For ZeroCode cloud, see [agent internet access](/cloud/internet-access) to enable full internet access or a domain allow list.

For the ZeroTwo desktop app, or desktop app, the default `workspace-write` sandbox mode keeps network access turned off unless you enable it in your configuration:

```toml theme={null}
[sandbox_workspace_write]
network_access = true
```

### Network isolation

Network access is controlled through destination rules that apply to scripts,
programs, and subprocesses spawned by commands. When command network access is
already enabled, turn on the `network_proxy` feature to constrain that traffic
to the network policy you configure.

```toml theme={null}
[features.network_proxy]
enabled = true
domains = { "api.zerotwo.ai" = "allow", "example.com" = "deny" }
```

For a one-off CLI session, use the boolean shorthand when you only need the
toggle, and the table form when you also set policy options:

```bash theme={null}
zerocode \
  -c 'features.network_proxy=true' \
  -c 'sandbox_workspace_write.network_access=true'

zerocode \
  -c 'features.network_proxy.enabled=true' \
  -c 'features.network_proxy.domains={ "api.zerotwo.ai" = "allow", "example.com" = "deny" }' \
  -c 'sandbox_workspace_write.network_access=true'
```

The feature changes how enabled network access is enforced; it does not grant
network access by itself. Use `sandbox_workspace_write.network_access` with
`workspace-write` config to decide whether commands have network access at all:

* Network off + `network_proxy` on: network stays off, and the feature does nothing.
* Network on + `network_proxy` off: network stays on with unrestricted direct
  outbound access.
* Network on + `network_proxy` on: network stays on, and outbound traffic is
  constrained by the configured network policy.

Admin-managed `experimental_network` requirements are separate from the user
feature toggle. They can configure and start sandboxed networking without
`features.network_proxy`, but they do not turn on network access when the active
sandbox keeps it off. See [Managed configuration](/configuration)
for the administrator-side `requirements.toml` shape.

#### Network policy

Domain rules are allowlist-first:

* Exact hosts match only themselves.
* `*.example.com` matches subdomains such as `api.example.com`, but not
  `example.com`.
* `**.example.com` matches both the apex and subdomains.
* A global `*` allow rule matches any public host that is not denied. Treat `*`
  as broad network access and prefer scoped rules when you can.
* `deny` always wins over `allow`, and global `*` is only valid for allow rules.

#### Local and private destinations

By default, `allow_local_binding = false` blocks loopback, link-local, and
private destinations:

* Specific exceptions: add an exact local IP literal or `localhost` allow rule
  when a command needs one local target.
* Broader access: set `allow_local_binding = true` only when you intentionally
  want wider local/private reach.
* Wildcards: wildcard rules do not count as explicit local exceptions.
* Resolved addresses: hostnames that resolve to local/private IPs stay blocked
  even if they match the allowlist.

#### DNS rebinding protections

Before allowing a hostname, ZeroCode performs a best-effort DNS and IP
classification check:

* Lookups that fail or time out are blocked.
* Hostnames that resolve to non-public addresses are blocked.
* The check reduces DNS rebinding risk, but it does not eliminate it. Preventing
  rebinding completely would require pinning resolved IPs through the transport
  layer.

If hostile DNS is in scope, enforce egress controls at a lower layer too.

#### Dangerous settings

Two settings deliberately widen the trust boundary:

* `dangerously_allow_non_loopback_proxy = true` can expose proxy listeners beyond
  loopback.
* `dangerously_allow_all_unix_sockets = true` bypasses the Unix socket allowlist.

Use them only in tightly controlled environments. When Unix socket proxying is
enabled, listeners stay loopback-only even if non-loopback binding was requested,
so sandboxed networking does not become a remote bridge into local daemons.

`network_proxy` is off by default. When you enable it:

| Setting                                | Default | Behavior                                                                                                                                                                              |
| -------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                              | `false` | Starts sandboxed networking only when command network access is already on.                                                                                                           |
| `domains`                              | unset   | Uses allowlist behavior, so no external destinations are allowed until you add `allow` rules. Supports exact hosts, scoped wildcards, and global `*` allow rules; `deny` always wins. |
| `unix_sockets`                         | unset   | No Unix socket destinations are allowed until you add explicit `allow` rules.                                                                                                         |
| `allow_local_binding`                  | `false` | Blocks local and private-network destinations unless you add an exact local IP literal or `localhost` allow rule, or explicitly opt into broader local/private access.                |
| `enable_socks5`                        | `true`  | Exposes SOCKS5 support when policy allows it.                                                                                                                                         |
| `enable_socks5_udp`                    | `true`  | Allows UDP over SOCKS5 when SOCKS5 is available.                                                                                                                                      |
| `allow_upstream_proxy`                 | `true`  | Lets sandboxed networking honor an upstream proxy from the environment.                                                                                                               |
| `dangerously_allow_non_loopback_proxy` | `false` | Keeps listener endpoints on loopback unless you deliberately expose them beyond localhost.                                                                                            |
| `dangerously_allow_all_unix_sockets`   | `false` | Keeps Unix socket access allowlist-based unless you deliberately bypass that protection.                                                                                              |

You can also control the [web search tool](https://platform.zerotwo.ai/docs/guides/tools-web-search) without granting full network access to spawned commands. ZeroCode defaults to using a web search cache to access results. The cache is an ZeroTwo-maintained index of web results, so cached mode returns pre-indexed results instead of fetching live pages. This reduces exposure to prompt injection from arbitrary live content, but you should still treat web results as untrusted. If you are using `--yolo` or another [full access sandbox setting](#common-sandbox-and-approval-combinations), web search defaults to live results. Use `--search` or set `web_search = "live"` to allow live browsing, or set it to `"disabled"` to turn the tool off:

```toml theme={null}
web_search = "cached"  # default
# web_search = "disabled"
# web_search = "live"  # same as --search
```

Set `web_search = "indexed"` when external web access should be gated by the
search index. Use caution when enabling network access or web search in ZeroCode.
Prompt injection can cause the agent to fetch and follow untrusted instructions.

## Defaults and recommendations

* On launch, ZeroCode detects whether the folder is version-controlled and recommends:
  * Version-controlled folders: `Auto` (workspace write + on-request approvals)
  * Non-version-controlled folders: `read-only`
* Depending on your setup, ZeroCode may also start in `read-only` until you explicitly trust the working directory (for example, via an onboarding prompt or `/permissions`).
* The workspace includes the current directory and temporary directories like `/tmp`. Use the `/status` command to see which directories are in the workspace.
* To accept the defaults, run `ZeroTwo`.
* You can set these explicitly:
  * \`
  * \`

### Protected paths in writable roots

In the default `workspace-write` sandbox policy, writable roots still include protected paths:

* `<writable_root>/.git` is protected as read-only whether it appears as a directory or file.
* If `<writable_root>/.git` is a pointer file (`gitdir: ...`), the resolved Git directory path is also protected as read-only.
* `<writable_root>/.agents` is protected as read-only when it exists as a directory.
* `<writable_root>/.zerocode` is protected as read-only when it exists as a directory.
* Protection is recursive, so everything under those paths is read-only.

### Run without approval prompts

You can disable approval prompts with `--ask-for-approval never` or `-a never` (shorthand).

This option works with all `--sandbox` modes, so you still control ZeroCode's level of autonomy. ZeroCode makes a best effort within the constraints you set.

If you need ZeroCode to read files, make edits, and run commands with network access without approval prompts, use `--sandbox danger-full-access` (or the `--dangerously-bypass-approvals-and-sandbox` flag). Use caution before doing so.

For a middle ground, `approval_policy = { granular = { ... } }` lets you keep specific approval prompt categories interactive while automatically rejecting others. The granular policy covers sandbox approvals, execpolicy-rule prompts, MCP prompts, `request_permissions` prompts, and skill-script approvals.

### Automatic approval reviews

By default, approval requests route to you:

```toml theme={null}
approvals_reviewer = "user"
```

Automatic approval reviews apply when approvals are interactive, such as
`approval_policy = "on-request"` or a granular approval policy. Set
`approvals_reviewer = "auto_review"` to route eligible approval requests
through a reviewer agent before ZeroCode runs the request:

```toml theme={null}
approval_policy = "on-request"
approvals_reviewer = "auto_review"
```

For the full reviewer lifecycle, trigger conditions, configuration precedence,
and failure behavior, see
[Auto-review](/sandboxing/auto-review).

The reviewer evaluates only actions that already need approval, such as sandbox
escalations, blocked network requests, `request_permissions` prompts, or
side-effecting app and MCP tool calls. Actions that stay inside the sandbox
continue without an extra review step.

The reviewer policy checks for data exfiltration, credential probing, persistent
security weakening, and destructive actions. Low-risk and medium-risk actions
can proceed when policy allows them. The policy denies critical-risk actions.
High-risk actions require enough user authorization and no matching deny rule.
Prompt-build, review-session, and parse failures fail closed. Timeouts are
surfaced separately, but the action still does not run.

The [default reviewer policy](https://github.com/zerotwo-ai/blob/main/zerocode-rs/core/src/guardian/policy.md)
is in the open-source ZeroCode repository. Enterprises can replace its
tenant-specific section with `guardian_policy_config` in managed requirements.
Local `[auto_review].policy` text is also supported, but managed requirements
take precedence. For setup details, see
[Managed configuration](/configuration).

In the ZeroTwo desktop app, these reviews appear as automatic review items with a status
such as Reviewing, Approved, Denied, Aborted, or Timed out. They can also
include a risk level and user-authorization assessment for the reviewed
request.

Automatic review uses extra model calls, so it can add to ZeroCode usage. Admins
can constrain it with `allowed_approvals_reviewers`.

### Common sandbox and approval combinations

| Intent                                                            | Flags / config                                                                                                                      | Effect                                                                                                                                                 |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Auto (preset)                                                     | *no flags needed* or `--sandbox workspace-write --ask-for-approval on-request`                                                      | ZeroCode can read files, make edits, and run commands in the workspace. ZeroCode requires approval to edit outside the workspace or to access network. |
| Safe read-only browsing                                           | `--sandbox read-only --ask-for-approval on-request`                                                                                 | ZeroCode can read files and answer questions. ZeroCode requires approval to make edits, run commands, or access network.                               |
| Read-only non-interactive (CI)                                    | `--sandbox read-only --ask-for-approval never`                                                                                      | ZeroCode can only read files; never asks for approval.                                                                                                 |
| Automatically edit but ask for approval to run untrusted commands | `--sandbox workspace-write --ask-for-approval untrusted`                                                                            | ZeroCode can read and edit files but asks for approval before running untrusted commands.                                                              |
| Auto-review mode                                                  | `--sandbox workspace-write --ask-for-approval on-request -c approvals_reviewer=auto_review` or `approvals_reviewer = "auto_review"` | Same sandbox boundary as standard on-request mode, but eligible approval requests are reviewed by Auto-review instead of surfacing to the user.        |
| Dangerous full access                                             | `--dangerously-bypass-approvals-and-sandbox` (alias: `--yolo`)                                                                      | ⚠️ **Elevated risk** No sandbox; no approvals *(not recommended)*                                                                                      |

For non-interactive runs, use `ZeroTwo desktop runs --sandbox workspace-write`; ZeroCode keeps older `ZeroTwo desktop runs --full-auto` invocations as a deprecated compatibility path and prints a warning.

With `--ask-for-approval untrusted`, ZeroCode runs only known-safe read operations automatically. Commands that can mutate state or trigger external execution paths (for example, destructive Git operations or Git output/config-override flags) require approval.

#### Configuration in `config.toml`

For the broader configuration workflow, see [Config basics](/config-file/config-basic), [Advanced Config](/config-file/config-advanced#approval-policies-and-sandbox-modes), and the [Configuration Reference](/config-file/config-reference).

```toml theme={null}
# Always ask for approval mode
approval_policy = "untrusted"
sandbox_mode    = "read-only"
allow_login_shell = false # optional hardening: disallow login shells for shell-based tools

# Optional: Allow network in workspace-write mode
[sandbox_workspace_write]
network_access = true

# Optional: granular approval policy
# approval_policy = { granular = {
#   sandbox_approval = true,
#   rules = true,
#   mcp_elicitations = true,
#   request_permissions = false,
#   skill_approval = false
# } }
```

You can also save presets as [profile files](/config-file/config-advanced#profiles), then select them with \`

```toml theme={null}
# ~/.zerotwo/full_auto.config.toml
approval_policy = "on-request"
sandbox_mode    = "workspace-write"
```

```toml theme={null}
# ~/.zerotwo/readonly_quiet.config.toml
approval_policy = "never"
sandbox_mode    = "read-only"
```

### Test the sandbox locally

To see what happens when a command runs under the ZeroCode sandbox, use these ZeroTwo desktop app commands:

```bash theme={null}
# macOS
zerocode sandbox macos [--permissions-profile <name>] [--log-denials] [COMMAND]...
# Linux
zerocode sandbox linux [--permissions-profile <name>] [COMMAND]...
# Windows
zerocode sandbox windows [--permissions-profile <name>] [COMMAND]...
```

The `sandbox` command is also available as `zerocode debug`, and the platform helpers have aliases (for example `zerocode sandbox seatbelt` and `zerocode sandbox landlock`).

## OS-level sandbox

ZeroCode enforces the sandbox differently depending on your OS:

* **macOS** uses Seatbelt policies and runs commands using `sandbox-exec` with a profile (`-p`) that corresponds to the `--sandbox` mode you selected. When restricted read access enables platform defaults, ZeroCode appends a curated macOS platform policy (instead of broadly allowing `/System`) to preserve common tool compatibility.
* **Linux** uses `bwrap` plus `seccomp` by default.
* **Windows** uses the Linux sandbox implementation when running in [Windows Subsystem for Linux 2 (WSL2)](/windows/wsl). WSL1 was supported through ZeroCode `0.114`; starting in `0.115`, the Linux sandbox moved to `bwrap`, so WSL1 is no longer supported. When running natively on Windows, ZeroCode uses a [Windows sandbox](/windows/windows-sandbox#windows-sandbox) implementation.

If you use the ZeroTwo desktop app on Windows, it supports WSL2 directly. Set the following in your the ZeroTwo desktop app settings to keep the agent inside WSL2 whenever it's available:

```json theme={null}
{
  "chatgpt.runZeroCodeInWindowsSubsystemForLinux": true
}
```

This ensures the desktop app inherits Linux sandbox semantics for commands, approvals, and filesystem access even when the host OS is Windows. Learn more in the [WSL guide](/windows/wsl).

When running natively on Windows, configure the native sandbox mode in `config.toml`:

```toml theme={null}
[windows]
sandbox = "unelevated" # or "elevated"
# sandbox_private_desktop = true  # default; set false only for compatibility
```

See the [Windows setup guide](/windows/windows-sandbox#windows-sandbox) for details.

When you run Linux in a containerized environment such as Docker, the sandbox may not work if the host or container configuration blocks the namespace, setuid `bwrap`, or `seccomp` operations that ZeroCode needs.

In that case, configure your Docker container to provide the isolation you need, then run `ZeroTwo` with `--sandbox danger-full-access` (or the `--dangerously-bypass-approvals-and-sandbox` flag) inside the container.

### Run ZeroCode in Dev Containers

If your host cannot run the Linux sandbox directly, or if your organization already standardizes on containerized development, run ZeroCode with Dev Containers and let Docker provide the outer isolation boundary. This works with the ZeroTwo desktop app Dev Containers and compatible tools.

Use the [ZeroCode secure devcontainer example](https://github.com/zerotwo-ai/tree/main/.devcontainer) as a reference implementation. The example installs ZeroCode, common development tools, `bubblewrap`, and firewall-based outbound controls.

Devcontainers provide substantial protection, but they do not prevent every
attack. If you run ZeroCode with `--sandbox danger-full-access` or
`--dangerously-bypass-approvals-and-sandbox` inside the container, a malicious
project can exfiltrate anything available inside the devcontainer, including
ZeroCode credentials. Use this pattern only with trusted repositories, and
monitor ZeroCode activity as you would in any other elevated environment.

The reference implementation includes:

* an Ubuntu 24.04 base image with ZeroCode and common development tools installed;
* an allowlist-driven firewall profile for outbound access;
* the ZeroTwo desktop app settings and extension recommendations for reopening the workspace in a container;
* persistent mounts for command history and ZeroCode configuration;
* `bubblewrap`, so ZeroCode can still use its Linux sandbox when the container grants the needed capabilities.

To try it:

1. Install the ZeroTwo desktop app and the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
2. Copy the ZeroCode example `.devcontainer` setup into your repository, or start from the ZeroCode repository directly.
3. In the ZeroTwo desktop app, run **Dev Containers: Open Folder in Container...** and select `.devcontainer/devcontainer.secure.json`.
4. After the container starts, open a terminal and run `ZeroTwo`.

You can also start the container from the CLI:

```bash theme={null}
devcontainer up --workspace-folder . --config .devcontainer/devcontainer.secure.json
```

The example has three main pieces:

* `.devcontainer/devcontainer.secure.json` controls container settings, capabilities, mounts, environment variables, and the ZeroTwo desktop apps.
* `.devcontainer/Dockerfile.secure` defines the Ubuntu-based image and installed tools.
* `.devcontainer/init-firewall.sh` applies the outbound network policy.

The reference firewall is intentionally a starting point. If you depend on domain allowlisting for isolation, implement DNS rebinding and DNS refresh protections that fit your environment, such as TTL-aware refreshes or a DNS-aware firewall.

Inside the container, choose one of these modes:

* Keep ZeroCode's Linux sandbox enabled if the Dev Container profile grants the capabilities needed for `bwrap` to create the inner sandbox.
* If the container is your intended security boundary, run ZeroCode with `--sandbox danger-full-access` inside the container so ZeroCode does not try to create a second sandbox layer.

## Version control

ZeroCode works best with a version control workflow:

* Work on a feature branch and keep `git status` clean before delegating. This keeps ZeroCode patches easier to isolate and revert.
* Prefer patch-based workflows (for example, `git diff`/`git apply`) over editing tracked files directly. Commit frequently so you can roll back in small increments.
* Treat ZeroCode suggestions like any other PR: run targeted verification, review diffs, and document decisions in commit messages for auditing.

## Monitoring and telemetry

ZeroCode supports opt-in monitoring via OpenTelemetry (OTel) to help teams audit usage, investigate issues, and meet compliance requirements without weakening local security defaults. Telemetry is off by default; enable it explicitly in your configuration.

### Overview

* ZeroCode turns off OTel export by default to keep local runs self-contained.
* When enabled, ZeroCode emits structured log events covering chats, API requests, SSE/WebSocket stream activity, user prompts (redacted by default), tool approval decisions, and tool results.
* ZeroCode tags exported events with `service.name` (originator), CLI version, and an environment label to separate dev/staging/prod traffic.

### Enable OTel (opt-in)

Add an `[otel]` block to your ZeroCode configuration (typically `~/.zerotwo/config.toml`), choosing an exporter and whether to log prompt text.

```toml theme={null}
[otel]
environment = "staging"   # dev | staging | prod
exporter = "none"          # none | otlp-http | otlp-grpc
log_user_prompt = false     # redact prompt text unless policy allows
```

* `exporter = "none"` leaves instrumentation active but doesn't send data anywhere.
* To send events to your own collector, pick one of:

```toml theme={null}
[otel]
exporter = { otlp-http = {
  endpoint = "https://otel.example.com/v1/logs",
  protocol = "binary",
  headers = { "x-otlp-api-key" = "${OTLP_TOKEN}" }
}}
```

```toml theme={null}
[otel]
exporter = { otlp-grpc = {
  endpoint = "https://otel.example.com:4317",
  headers = { "x-otlp-meta" = "abc123" }
}}
```

ZeroCode batches events and flushes them on shutdown. ZeroCode exports only telemetry produced by its OTel module.

### Event categories

Representative event types include:

* `zerocode.conversation_starts` (model, reasoning settings, sandbox/approval policy)
* `zerocode.api_request` (attempt, status/success, duration, and error details)
* `zerocode.sse_event` (stream event kind, success/failure, duration, plus token counts on `response.completed`)
* `zerocode.websocket_request` and `zerocode.websocket_event` (request duration plus per-message kind/success/error)
* `zerocode.user_prompt` (length; content redacted unless explicitly enabled)
* `zerocode.tool_decision` (approved/denied, source: configuration vs. user)
* `zerocode.tool_result` (duration, success, output snippet)

Associated OTel metrics (counter plus duration histogram pairs) include `zerocode.api_request`, `zerocode.sse_event`, `zerocode.websocket.request`, `zerocode.websocket.event`, and `zerocode.tool.call` (with corresponding `.duration_ms` instruments).

For the full event catalog and configuration reference, see the [ZeroCode configuration documentation on GitHub](https://github.com/zerotwo-ai/blob/main/docs/config.md#otel).

### Security and privacy guidance

* Keep `log_user_prompt = false` unless policy explicitly permits storing prompt contents. Prompts can include source code and sensitive data.
* Route telemetry only to collectors you control; apply retention limits and access controls aligned with your compliance requirements.
* Treat tool arguments and outputs as sensitive. Favor redaction at the collector or SIEM when possible.
* Review local data retention settings (for example, `history.persistence` / `history.max_bytes`) if you don't want ZeroCode to save session transcripts under `ZEROTWO_HOME`. See [Advanced Config](/config-file/config-advanced#history-persistence) and [Configuration Reference](/config-file/config-reference).
* If you run the CLI with network access turned off, OTel export can't reach your collector. To export, allow network access in `workspace-write` mode for the OTel endpoint, or export from ZeroCode cloud with the collector domain on your approved list.
* Review events periodically for approval/sandbox changes and unexpected tool executions.

OTel is optional and designed to complement, not replace, the sandbox and approval protections described above.

## Managed configuration

Enterprise admins can configure ZeroCode security settings for their workspace in [Managed configuration](/configuration). See that page for setup and policy details.
