Golem docs

Protect

Shell jail and sandbox

A kernel jail around every shell command an agent runs, and a throwaway VM for work that reads what a stranger wrote.

Rules decide whether a call runs. These two decide what a call can reach once it does. The shell jail wraps every shell command a Claude Code session runs on a Mac, so a command an agent was talked into still cannot read your keys or switch Golem off. The sandbox gives an agent somewhere else to do the riskiest work: reading a page from an issue, running a repository from a pull request, opening a download nobody vetted.

Shell jailSandbox
Runsevery shell command a Claude Code session runswhen an agent calls sandbox_browse, sandbox_run or sandbox_open
BoundarymacOS's own kernel sandbox, around the command and everything it startsa throwaway Linux VM per task, on the same Mac
Keepsyour real toolchain, repositories, ssh, git signing, Docker, cloud CLIsnothing of yours beyond what the agent hands over
NeedsmacOS, Claude CodeApple silicon, macOS 26 or later, Claude Code installed
Defaultonon, once installed

The shell jail#

What you do#

Nothing, on a Mac. The installer puts Golem's shell into ~/.golem/bin and points Claude Code at it by setting CLAUDE_CODE_SHELL in the env block of ~/.claude/settings.json (to golem-zsh, or golem-bash if your login shell is bash). If you already set CLAUDE_CODE_SHELL to something else, Golem leaves it alone and the jail does not apply; golem doctor is the place to check. Restart Claude Code after installing so it picks the setting up.

How it works#

Before each command starts, Golem's shell asks the Golem agent on the machine for this session's policy, turns it into a macOS sandbox profile and applies it to the shell process itself. The command string is never parsed or rewritten. Because the jail is on the process, everything the command starts inherits it: an absolute /bin/bash, nohup … &, python -c, a script piped to sh.

flowchart TD
    A["Claude Code Bash tool"] --> S["Golem's shell"]
    S -- "session policy?" --> G["Golem agent"]
    G -- "clean or locked down, grants" --> S
    S --> Z["the command, inside the kernel sandbox"]
    Z -. "refusals" .-> G
    G --> L[("Signed record")]

What a command cannot do#

ReadPrivate keys, judged by their contents rather than their names, so a key called google_compute_engine or a deploy key is covered. Shell history (~/.zsh_history, ~/.bash_history, ~/.zsh_sessions), ~/.netrc, ~/.git-credentials, GnuPG private keys and ~/.golem.
Still readThe rest of ~/.ssh: config, included files, known hosts and public keys, so ssh keeps working.
WriteYour shell profiles (~/.zshrc, ~/.bashrc, ~/.profile and the rest), ~/.gitconfig, ~/Library/LaunchAgents, ~/.ssh, ~/.golem, Claude Code's settings and hooks (including the repository's .claude/settings.json), and Cursor's hooks and MCP files. A hijacked command cannot switch Golem off or leave something behind to run at the next login.
SeeEnvironment variables whose names look like secrets (containing TOKEN, SECRET, PASSWORD, API_KEY, CREDENTIAL, ACCESS_KEY, COOKIE and similar, or starting GH_, GITHUB_, ANTHROPIC_, OPENAI_) are stripped before the command starts.

What keeps working#

Three grants, each on by default, keep normal development working. An owner or admin can turn each one off.

GrantWhat it allowsTurned off
SSH agent and keychaingit push, gh, commit signing, through the ssh agent and keychain. The key files stay unreadable either way.The agent socket, the keychain and gh's token file are denied.
DockerThe Docker socket (Docker Desktop, OrbStack, Rancher, Colima).Denied. Worth considering: a container can mount the machine, which gets around the jail.
Cloud credentials~/.aws, ~/.config/gcloud, ~/.kube, ~/.azure, registry credentials in ~/.docker/config.json, ~/.npmrc, ~/.pypirc, and their environment variables.Denied, and the variables are stripped.

Two lists adjust the stripping: Let these variables through (for example NPM_TOKEN, or a prefix like MYCO_*) and Always strip these variables. Strip wins over let through.

Lockdown#

A rule can respond by locking a session down. From then until a fresh session starts, every shell command in it runs with:

  • no network at all, localhost and DNS included;
  • no grants: no ssh agent, keychain, Docker or cloud credentials, and the let-through list ignored;
  • writes only inside the repository it is working in and its own temporary directory, with the repository's git hooks and git config still unwritable.

Lockdown only tightens. Nothing inside the session can lift it. /safely and a quarantined machine also lock the shell down.

Three starter rules can lock a session down, and all three ship off, because people sometimes ask their agent to read the web or edit ~/.zshrc on purpose:

  • Lock down the shell after a web fetch.
  • Lock down the shell after a prompt injection (the prompt-injection check scores a result at 0.98 or higher; the check itself must be on).
  • Lock down the shell after a jail denial.

They are listed on the Sandbox settings under Lock down a session. See Rules and CEL for writing your own.

Settings#

In the console, Sandbox, then Settings at the top right, card Shell commands:

  • Jail agent shells turns the jail on or off for every Mac in the workspace.
  • The three grants, and the two variable lists.

To change them for one group of machines or one machine, set the Sandbox: shell commands section on a profile under Fleet. Only owners and admins can change these, and a change reaches machines in about 30 seconds.

Cost, and if Golem stops#

A jailed command starts about 30 ms later than it would bare. Golem's shell waits at most 250 ms for the session's policy. If the Golem agent does not answer in time, it uses the last policy it had for this session, then the machine's last known policy, then a baseline. In every case credential stores and persistence writes stay denied. It never runs a command unjailed because the Golem agent is down. The network is open in that fallback unless the session's cached policy was a lockdown.

On the record#

Each command is recorded, and each operation the kernel refuses is signed into the session as a shield_denied entry naming the command that tried it. A lockdown is signed as shield_tainted, with the rule that caused it. The console's Sandbox page shows, per day: coverage (sessions whose shell commands ran jailed), jailed commands, refusals, sessions locked down, commands run without the Golem agent, and commands that ran outside the jail. Refusals also appear in Events under the Sandbox: shell lens.

What the jail does not cover#

  • It is macOS only, and Claude Code only. Linux and Windows are not supported yet. Other agents' shell commands are not jailed; their hooks and rules still apply.
  • Claude Code's own Read, Write and Edit tools do not go through a shell, so the jail does not see them. Rules on those tools still apply.
  • Commands you type in your own terminal are not jailed.
  • A clean session has open network access. Only a lockdown takes it away.
  • Programs that need setuid (rare in agent work) fail inside the jail.

The sandbox#

What you do#

On a Mac with Apple silicon and macOS 26 or later, the installer sets the sandbox up. It installs Apple's open-source container tool, checked against a pinned checksum and Apple's signature, and asks for your password once. Under MDM, running as root, it installs without asking. To skip it, set GOLEM_NO_SANDBOX=1 when installing; to add it later, run:

golem install sandbox

On any other machine it reports that the sandbox is not supported and does nothing. The child agent is a Claude Code session, so Claude Code must be installed.

Golem also installs a golem-sandbox skill for Claude Code, Cursor, Codex, Copilot and Antigravity, which tells the agent when to reach for these tools: before fetching a URL from an issue or chat, before reading a repository or package it did not write, before opening a file from outside the project. You can ask for it directly too.

The three tools#

ToolHand itNetworkReturns
sandbox_browsea url and a questionthe URL's host by default; hosts adds up to 20 morean answer to the question
sandbox_runa task, and a local path or an https repo to work onnone by default; hosts opens named hostsan answer, and a patch for the agent to review before applying
sandbox_openup to 20 file paths and a questionnone by defaultwhat it found

Every result also carries a deviations list: each thing the child tried that it was not allowed to. An egress_denied entry names the method, host and port and why it was refused, for example host_not_in_lockdown. Other kinds are browse_denied, guard_blocked (the child tried a tool it does not have) and token_cap. The answer is marked as written by an agent that read untrusted content.

How it is isolated#

  • The pages it loads, commands it runs and files it reads run in a fresh Linux VM with no network of its own, a read-only root, no capabilities and an unprivileged user. Its one way out is Golem's egress proxy, which allows only the hosts named and ports 80 and 443, and refuses private addresses.
  • No credentials. Files go in read-only, and Golem refuses to hand over your home directory or a credentials directory. A repository is cloned inside.
  • The child agent is fenced to the sandbox's own tools: no Bash, file, web fetch or search tools of its own. It runs on your Claude Code sign-in, capped at 200,000 tokens per task.
  • Each VM is discarded when its work is done.

Isolation does not detect an injection. It limits what one can reach. So the child is watched like any other agent: its calls and every network request its VM makes are signed into the same record, linked to the session that handed the work over.

Limits#

sandbox_open20 files, 100 MB each, 500 MB in all
A command inside sandbox_run2 minutes by default, 10 at most
A whole task5 minutes by default for browse and open (10 at most for open), 10 for run (30 at most)
A returned patchabout 100 KB

Settings#

The sandbox is one switch for the workspace: Sandbox, then Settings, card Sandbox. It is on by default. Turned off, the three tools disappear from every agent's tool list.

Updated 2026-10-14 · This page as Markdown