diff --git a/documentation/docs/guides/environment-variables.md b/documentation/docs/guides/environment-variables.md index 99db4c422658..fb721a129942 100644 --- a/documentation/docs/guides/environment-variables.md +++ b/documentation/docs/guides/environment-variables.md @@ -430,6 +430,14 @@ When the keyring is disabled (or cannot be accessed and goose [falls back to fil * Windows: `%APPDATA%\Block\goose\config\secrets.yaml` ::: +### macOS Sandbox for goose Desktop + +Optional [macOS sandbox](/docs/guides/sandbox) for goose Desktop that restricts file access, network connections, and process execution using Apple's `sandbox-exec` technology. + +| Variable | Purpose | Values | Default | +|----------|---------|--------|---------| +| `GOOSE_SANDBOX` | Enable the sandbox with [customizable security controls](/docs/guides/sandbox#configuration) | `true` or `1` to enable | `false` | + ## Network Configuration These variables configure network proxy settings for goose. diff --git a/documentation/docs/guides/sandbox.md b/documentation/docs/guides/sandbox.md index 71b1d77fb887..8d185f9fd920 100644 --- a/documentation/docs/guides/sandbox.md +++ b/documentation/docs/guides/sandbox.md @@ -1,83 +1,116 @@ -# macOS Sandbox for goosed +--- +title: macOS Sandbox for goose Desktop +sidebar_label: Sandbox for goose Desktop +description: Optional sandboxing for goose Desktop to control file access, filter network traffic, and enforce security policies on macOS +--- -goose includes an optional macOS sandbox that restricts the goosed process using Apple's seatbelt (`sandbox-exec`) and routes all network traffic through a local egress proxy. This limits what the agent can do on your system — blocking sensitive file writes, raw sockets, tunneling tools, and unapproved network destinations. +goose Desktop includes an optional macOS sandbox that you can enable when you need stricter control and visibility over what goose can access on your system. Use it to: -> **Requirements:** macOS only. The sandbox relies on `/usr/bin/sandbox-exec` which is only available on macOS. +- **Restrict file system access** — Block writes to SSH keys, shell configs, and goose configuration files +- **Control network connections** — Force all traffic through a filtering proxy that blocks unapproved domains +- **Prevent security bypasses** — Block tunneling tools, raw sockets, and other techniques that could circumvent restrictions +- **Audit and enforce policies** — Log all network activity and enforce compliance requirements + +goose runs with full tool access, but the sandbox uses two layers of protection: +- **File access control** - Apple's `sandbox-exec` restricts file and network access at the system level +- **Outbound connections** - A local egress proxy filters and logs outgoing connections + +:::info macOS Requirement +The sandbox relies on `/usr/bin/sandbox-exec`, which is only available on macOS and is also known as Apple's seatbelt technology. +::: ## Quick Start -Set the environment variable before launching the goose desktop app: +To enable the sandbox, launch goose Desktop from the terminal with the environment variable set. For example: ```bash -GOOSE_SANDBOX=true +export GOOSE_SANDBOX=true +open -a Goose ``` -Then start the desktop app as normal. goose will: +When the app starts with sandboxing enabled, it will: 1. Generate a seatbelt sandbox profile 2. Start a local HTTP CONNECT proxy on localhost -3. Launch goosed inside `sandbox-exec`, forcing all traffic through the proxy +3. Launch the `goosed` backend for goose Desktop inside `sandbox-exec`, forcing all traffic through the proxy -If `sandbox-exec` is not available (e.g. you're on Linux), goose will fail fast with a clear error rather than running unsandboxed. +The sandbox remains active until you quit goose Desktop. To disable it, quit the app and relaunch normally (or set `GOOSE_SANDBOX=false` when opening from the terminal). -## What Gets Restricted +## Configuration -### File System (seatbelt) +All configuration is via environment variables. Defaults are designed to be secure out of the box, but you can adjust them to match your security requirements. -By default, the sandbox blocks writes to: +### Core -| Path | Purpose | -|------|---------| -| `~/.ssh/` | Prevent SSH key tampering | -| `~/.bashrc`, `~/.zshrc`, `~/.bash_profile`, `~/.zprofile` | Prevent shell config injection | -| `~/.config/goose/sandbox/` | Protect sandbox config from the sandboxed process | -| `~/.config/goose/config.yaml` | Protect goose config | +| Variable | Default | Description | +|----------|---------|-------------| +| `GOOSE_SANDBOX` | `false` | Set to `true` or `1` to enable the sandbox. See [Quick Start](#quick-start) for launch instructions. | -### Network (seatbelt) +---- -All direct network access is denied. The only allowed paths are: +### File System -- **Localhost** — so the process can reach the egress proxy and its own server port -- **Unix sockets** — for local IPC -- **mDNSResponder** — for DNS resolution +The [seatbelt sandbox profile](https://github.com/block/goose/blob/main/ui/desktop/src/sandbox/index.ts) blocks write operations to these sensitive files: -Everything else must go through the proxy. +- `~/.ssh/` - Prevent SSH key tampering +- `~/.bashrc`, `~/.zshrc`, `~/.bash_profile`, `~/.zprofile` - Prevent shell config injection +- `~/.config/goose/sandbox/` - Protect sandbox config from the sandboxed process +- `~/.config/goose/config.yaml` - Protect goose config -### Process Restrictions (seatbelt) -- **Tunneling tools blocked:** `nc`, `ncat`, `netcat`, `socat`, `telnet` — prevents the agent from bypassing the proxy -- **Raw sockets blocked:** `SOCK_RAW` on `AF_INET`/`AF_INET6` — prevents raw packet crafting -- **Kernel extensions blocked:** `system-kext-load` denied +#### Environment Variables -### Network (proxy) +| Variable | Default | Description | +|----------|---------|-------------| +| `GOOSE_SANDBOX_PROTECT_FILES` | `true` | Write-protect sensitive files listed above. Set to `false` to disable | -The egress proxy checks connections in this order: +---- -1. **Loopback detection** — prevents using the proxy as a relay back to localhost -2. **Raw IP blocking** — connections to bare IP addresses (no domain) are blocked -3. **Domain blocklist** — domains listed in `blocked.txt` are denied (including all subdomains) -4. **SSH/Git host restrictions** — SSH ports (22, 2222, 7999) are restricted to known git hosts -5. **LaunchDarkly allowlist** (optional) — dynamic egress control via feature flag +### Direct Network Access -## Configuration +The seatbelt sandbox denies all direct network access, forcing traffic through the proxy. The only allowed connections are: -All configuration is via environment variables. Defaults are designed to be secure out of the box. +- **Localhost** — Allows the `goosed` process to reach the egress proxy and its own server port +- **Unix sockets** — For local inter-process communication (IPC) +- **mDNSResponder** — For DNS resolution -### Core +:::info Not Configurable +These restrictions are always active when the sandbox is enabled. +::: -| Variable | Default | Description | -|----------|---------|-------------| -| `GOOSE_SANDBOX` | `false` | Set to `true` or `1` to enable the sandbox | +---- + +### Process Restrictions + +The seatbelt sandbox blocks tools and system calls that could bypass security controls: -### Seatbelt Profile +- **Tunneling tools** — `nc`, `ncat`, `netcat`, `socat`, `telnet` are blocked to prevent bypassing the proxy +- **Raw sockets** — `SOCK_RAW` on `AF_INET`/`AF_INET6` is blocked to prevent raw packet crafting +- **Kernel extensions** — `system-kext-load` is denied + +#### Environment Variables | Variable | Default | Description | |----------|---------|-------------| -| `GOOSE_SANDBOX_PROTECT_FILES` | `true` | Write-protect `~/.ssh` and shell configs. Set to `false` to disable | | `GOOSE_SANDBOX_BLOCK_RAW_SOCKETS` | `true` | Block `SOCK_RAW`. Set to `false` to disable | | `GOOSE_SANDBOX_BLOCK_TUNNELING` | `true` | Block `nc`/`netcat`/`socat`/`telnet`. Set to `false` to disable | -### Proxy +---- + +### Network Filtering + +The egress proxy inspects and filters all outgoing connections. You can customize filtering rules through the blocklist file and configuration variables. + +The egress proxy checks connections in this order: + +1. **Loopback detection** — Prevents using the proxy as a relay back to localhost +2. **Raw IP blocking** — Connections to bare IP addresses (no domain) are blocked +3. **Domain blocklist** — Domains listed in `blocked.txt` are denied (including all subdomains) +4. **SSH/Git host restrictions** — SSH ports (22, 2222, 7999) are restricted to known git hosts + +For optional LaunchDarkly-based egress control, see [LaunchDarkly](#launchdarkly-optional). + +#### Environment Variables | Variable | Default | Description | |----------|---------|-------------| @@ -87,16 +120,7 @@ All configuration is via environment variables. Defaults are designed to be secu | `GOOSE_SANDBOX_GIT_HOSTS` | built-in list | Comma-separated list of allowed SSH git hosts (e.g. `github.com,gitlab.com`) | | `GOOSE_SANDBOX_SSH_ALL_HOSTS` | `false` | Set to `true` to allow SSH to any host (not just git hosts) | -### LaunchDarkly (optional — not required) - -LaunchDarkly is **not required**. The sandbox works fully without it using the local `blocked.txt` blocklist. These settings only apply if your organization uses LaunchDarkly for dynamic egress control. - -| Variable | Default | Description | -|----------|---------|-------------| -| `LAUNCHDARKLY_CLIENT_ID` | — | LD client SDK key to enable dynamic egress control | -| `GOOSE_SANDBOX_LD_FAILOVER` | — | Failover mode if LD is unreachable: `allow`, `deny`, or `blocklist` | - -## Domain Blocklist +#### Managing the Domain Blocklist The file `~/.config/goose/sandbox/blocked.txt` controls which domains are blocked by the proxy. It's created automatically on first run from a bundled template. @@ -109,13 +133,15 @@ transfer.sh webhook.site ``` -**Live reload:** Changes to `blocked.txt` take effect immediately — the proxy watches the file with `fs.watch` and reloads it automatically. No restart needed. +:::tip Live Reload +Changes to `blocked.txt` take effect immediately — the proxy watches the file with `fs.watch` and reloads it automatically. No restart needed. +::: -## SSH and Git +#### Using Git Over SSH -SSH git operations (`git clone git@github.com:...`) work through the sandbox via a bundled `connect-proxy.pl` script that acts as an SSH `ProxyCommand`. This routes SSH connections through the egress proxy, which then applies the same allowlist rules. +SSH git operations (e.g. `git clone git@github.com:...`) work through the sandbox via a bundled `connect-proxy.pl` script that acts as an SSH `ProxyCommand`. This routes SSH connections through the egress proxy, which then applies the same allowlist rules. -By default, SSH is only allowed to well-known git hosting domains (GitHub, GitLab, Bitbucket, etc.). To customise: +By default, SSH is only allowed to well-known git hosting domains (e.g. GitHub, GitLab, Bitbucket). To customize: ```bash # Add custom git hosts @@ -125,6 +151,19 @@ export GOOSE_SANDBOX_GIT_HOSTS="github.com,gitlab.com,your-gitea.internal.com" export GOOSE_SANDBOX_SSH_ALL_HOSTS=true ``` +---- + +### LaunchDarkly (Optional) + +For enterprise environments, LaunchDarkly provides optional dynamic egress control. If not configured, the sandbox uses the local `blocked.txt` blocklist. + +#### Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `LAUNCHDARKLY_CLIENT_ID` | — | LD client SDK key to enable dynamic egress control | +| `GOOSE_SANDBOX_LD_FAILOVER` | — | Failover mode if LD is unreachable: `allow`, `deny`, or `blocklist` | + ## Example Configurations ### Maximum security @@ -148,7 +187,7 @@ export GOOSE_SANDBOX=true export GOOSE_SANDBOX_ALLOW_SSH=false ``` -### Relaxed mode (sandbox on, fewer restrictions) +### Relaxed mode (fewer restrictions) ```bash export GOOSE_SANDBOX=true @@ -169,14 +208,15 @@ export GOOSE_SANDBOX_LD_FAILOVER=blocklist # fall back to local blocklist if LD ## Troubleshooting -**"GOOSE_SANDBOX=true but sandbox-exec is not available (macOS only)"** -You're not on macOS, or `/usr/bin/sandbox-exec` is missing. The sandbox only works on macOS. +- **Error: "GOOSE_SANDBOX=true but sandbox-exec is not available (macOS only)"** + You're not on macOS, or `/usr/bin/sandbox-exec` is missing. The sandbox only works on macOS. + +- **Extensions or tools can't reach the network** + Check if the destination domain is in `~/.config/goose/sandbox/blocked.txt`, or if you need to enable `GOOSE_SANDBOX_ALLOW_IP=true` for IP-based endpoints. -**Extensions or tools can't reach the network** -Check if the destination domain is in `~/.config/goose/sandbox/blocked.txt`, or if you need to enable `GOOSE_SANDBOX_ALLOW_IP=true` for IP-based endpoints. +- **git clone over SSH fails** + The target host may not be in the default Git hosts allowlist. Add it with `GOOSE_SANDBOX_GIT_HOSTS=your-host.com` or set `GOOSE_SANDBOX_SSH_ALL_HOSTS=true`. -**Git clone over SSH fails** -The target host may not be in the default git hosts allowlist. Add it with `GOOSE_SANDBOX_GIT_HOSTS=your-host.com` or set `GOOSE_SANDBOX_SSH_ALL_HOSTS=true`. +- **Want to inspect what the proxy is blocking?** + Check the [Desktop application logs](/docs/guides/logs#desktop-application-log). Blocked connections are logged with the prefix `[sandbox-proxy]` and include the reason for blocking. -**Want to inspect what the proxy is blocking?** -Check the Electron/goosed logs — blocked connections are logged with the reason. diff --git a/documentation/docs/guides/security/index.mdx b/documentation/docs/guides/security/index.mdx index 1905516d36bb..13e83a0da157 100644 --- a/documentation/docs/guides/security/index.mdx +++ b/documentation/docs/guides/security/index.mdx @@ -25,6 +25,11 @@ import styles from '@site/src/components/Card/styles.module.css'; description="API specification for self-hosting ML-based prompt injection detection endpoints." link="/docs/guides/security/classification-api-spec" /> +