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-execwhich 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:
- Generate a seatbelt sandbox profile
- Start a local HTTP CONNECT proxy on localhost
- 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:
| 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 |
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_RAWonAF_INET/AF_INET6— prevents raw packet crafting - Kernel extensions blocked:
system-kext-loaddenied
Network (proxy)
The egress proxy checks connections in this order:
- Loopback detection — prevents using the proxy as a relay back to localhost
- Raw IP blocking — connections to bare IP addresses (no domain) are blocked
- Domain blocklist — domains listed in
blocked.txtare denied (including all subdomains) - SSH/Git host restrictions — SSH ports (22, 2222, 7999) are restricted to known git hosts
- 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
| Variable | Default | Description |
|---|---|---|
GOOSE_SANDBOX | false | Set to true or 1 to enable the sandbox |
Seatbelt Profile
| 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
| Variable | Default | Description |
|---|---|---|
GOOSE_SANDBOX_ALLOW_IP | false | Set to true to allow connections to raw IP addresses |
GOOSE_SANDBOX_BLOCK_LOOPBACK | false | Set to true to block loopback relay through the proxy |
GOOSE_SANDBOX_ALLOW_SSH | true | Set to false to block all SSH traffic |
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
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.