Skip to main content

macOS Sandbox for goosed

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.

Requirements: macOS only. The sandbox relies on /usr/bin/sandbox-exec which is only available on macOS.

Quick Start

Set the environment variable before launching the goose desktop app:

GOOSE_SANDBOX=true

Then start the desktop app as normal. goose 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

If sandbox-exec is not available (e.g. you're on Linux), goose will fail fast with a clear error rather than running unsandboxed.

What Gets Restricted

File System (seatbelt)

By default, the sandbox blocks writes to:

PathPurpose
~/.ssh/Prevent SSH key tampering
~/.bashrc, ~/.zshrc, ~/.bash_profile, ~/.zprofilePrevent shell config injection
~/.config/goose/sandbox/Protect sandbox config from the sandboxed process
~/.config/goose/config.yamlProtect goose config

Network (seatbelt)

All direct network access is denied. The only allowed paths are:

  • Localhost — so the process can reach the egress proxy and its own server port
  • Unix sockets — for local IPC
  • mDNSResponder — for DNS resolution

Everything else must go through the proxy.

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

Network (proxy)

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

Configuration

All configuration is via environment variables. Defaults are designed to be secure out of the box.

Core

VariableDefaultDescription
GOOSE_SANDBOXfalseSet to true or 1 to enable the sandbox

Seatbelt Profile

VariableDefaultDescription
GOOSE_SANDBOX_PROTECT_FILEStrueWrite-protect ~/.ssh and shell configs. Set to false to disable
GOOSE_SANDBOX_BLOCK_RAW_SOCKETStrueBlock SOCK_RAW. Set to false to disable
GOOSE_SANDBOX_BLOCK_TUNNELINGtrueBlock nc/netcat/socat/telnet. Set to false to disable

Proxy

VariableDefaultDescription
GOOSE_SANDBOX_ALLOW_IPfalseSet to true to allow connections to raw IP addresses
GOOSE_SANDBOX_BLOCK_LOOPBACKfalseSet to true to block loopback relay through the proxy
GOOSE_SANDBOX_ALLOW_SSHtrueSet to false to block all SSH traffic
GOOSE_SANDBOX_GIT_HOSTSbuilt-in listComma-separated list of allowed SSH git hosts (e.g. github.com,gitlab.com)
GOOSE_SANDBOX_SSH_ALL_HOSTSfalseSet 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.

VariableDefaultDescription
LAUNCHDARKLY_CLIENT_IDLD client SDK key to enable dynamic egress control
GOOSE_SANDBOX_LD_FAILOVERFailover mode if LD is unreachable: allow, deny, or blocklist

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.

# One domain per line. Subdomains are blocked automatically.
# Lines starting with # are comments.
evil.com # blocks evil.com and *.evil.com
pastebin.com
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.

SSH and Git

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.

By default, SSH is only allowed to well-known git hosting domains (GitHub, GitLab, Bitbucket, etc.). To customise:

# Add custom git hosts
export GOOSE_SANDBOX_GIT_HOSTS="github.com,gitlab.com,your-gitea.internal.com"

# Or allow SSH to all hosts
export GOOSE_SANDBOX_SSH_ALL_HOSTS=true

Example Configurations

Maximum security

export GOOSE_SANDBOX=true
# All protections enabled (defaults)

Allow raw IP connections (e.g. for internal APIs)

export GOOSE_SANDBOX=true
export GOOSE_SANDBOX_ALLOW_IP=true

Disable SSH entirely

export GOOSE_SANDBOX=true
export GOOSE_SANDBOX_ALLOW_SSH=false

Relaxed mode (sandbox on, fewer restrictions)

export GOOSE_SANDBOX=true
export GOOSE_SANDBOX_PROTECT_FILES=false
export GOOSE_SANDBOX_BLOCK_RAW_SOCKETS=false
export GOOSE_SANDBOX_BLOCK_TUNNELING=false
export GOOSE_SANDBOX_ALLOW_IP=true
export GOOSE_SANDBOX_SSH_ALL_HOSTS=true

With LaunchDarkly egress control

export GOOSE_SANDBOX=true
export LAUNCHDARKLY_CLIENT_ID=sdk-your-key-here
export GOOSE_SANDBOX_LD_FAILOVER=blocklist # fall back to local blocklist if LD is down

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.

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.

Want to inspect what the proxy is blocking? Check the Electron/goosed logs — blocked connections are logged with the reason.