Runner security
What a runner's credential allows, how agents are isolated, the known gaps, and how to run agents safely in production.
A runner executes model-driven processes that read your code, run commands and call the SAT API. This page explains the trust boundaries as the code implements them today: the credential, what an agent process can reach, and what it can do through the API. It ends with recommendations, which are labelled as such. Read the known gaps before you run agents on a machine that holds anything you care about.
The runner's credential
A runner authenticates with a personal API key. sat runner start refuses a password session.
| Property | Behaviour |
|---|---|
| Format | sat_live_ followed by 32 URL-safe characters |
| Storage on the server | Only the SHA-256 hash, plus the first 13 characters (prefix) for display |
| Shown | Once, in the create response. It cannot be retrieved later |
| Identity | Authenticates as the member who created it, in every company that member belongs to. Keys have no company or permission scope |
| Expiry | Never, unless created with expires_in_days (1 to 3650) |
| Revocation | DELETE /api/me/api-keys/{key_id} or sat apikey revoke. Takes effect on the next request |
| Limits | 20 active keys per member; names unique among active keys. Revoked and expired keys do not count |
| Session-only actions | Creating and revoking keys (/api/me/api-keys and the legacy /api/users/{username}/api-keys routes) and signing out (POST /api/logout) refuse an API key with 403 SESSION_REQUIRED. Listing keys works with a key |
| User deactivated | The key stops working |
| Password reset | Ends every key created before the reset, along with all sessions. Create a new key for the runner afterwards |
last_used is updated at most once a minute per key. See API keys.
Why a key and not a session
Agents use the runner's credential through sat. A password session can create and revoke API keys, sign you out everywhere, and its refresh token can mint new access tokens. An API key can do none of these, and it can be revoked on its own without signing you out.
Known gap in key restrictions
Profile. PATCH /api/me and PATCH /api/me/preferences accept an API key, so an agent can change its owner's name, avatar and preferences.
What an agent process can reach
sat runner starts each agent as a child process of the runner, as the same operating-system user. It sets these protections:
- Empty
satconfiguration.SAT_CONFIG_DIRpoints at<workdir>/.sat-agent-config, an empty directory (mode 0700).SAT_CREDENTIAL_STORE=file,SAT_TOKENandSAT_PROFILEare cleared. The agent'ssattherefore sees no profiles and no stored credentials, onlySAT_API_KEY. - One workspace per run. Project runs get their own git worktree, so concurrent runs never edit the same checkout. See Workspaces.
- The agent CLI's own sandbox. Claude Code permission modes and Codex sandbox modes apply (below).
These protections do not make an agent a separate security principal:
- The agent inherits the runner's entire environment: provider keys such as
ANTHROPIC_API_KEY, cloud credentials,SSH_AUTH_SOCKand anything else set where the runner started. - Outside its CLI sandbox, the agent can read whatever the runner's user can read: the real
~/.config/satcredentials, other agents' workspaces and scratch folders, SSH keys, git credentials. - The empty configuration directory stops the agent's
satfrom using your stored session. It does not stop an agent with shell access from opening files directly.
What an agent can do through the API
Through sat and SAT_API_KEY, an agent has the full member powers of the key's owner. Agent-scoped credentials are not implemented. For example, an agent can:
- Create, assign, move and edit tasks, goals and projects, delete tasks and goals, and post comments, in any company the owner belongs to (
SAT_COMPANYis only a default). - Hire, edit, pause, resume, wake and terminate agents, including rewriting another agent's
instructions. - Cancel runs and trigger routines.
- Approve approvals, including its own
budget_override, which lifts its monthly budget. Any member may decide any approval. - Change the company's name, mission and budget, when the key's owner is an
owneroradmin. - Attribute writes to another agent by passing that agent's running run id as
run_id. The API checks only that the run isrunning.
Every write is in the activity log with its actor. Writes that pass run_id show the agent; others show the key's owner.
Members cannot be added yet
The API has no endpoint to add members to a company; the creator is its only member, with role owner. In practice the runner's key belongs to the company owner, with all of the owner's powers.
Permission modes and sandboxing
The agent CLI's permission or sandbox mode is the main control over what the agent does on the machine.
| Setting | Default | Effect | Use it |
|---|---|---|---|
--claude-permission-mode acceptEdits | Yes | File edits are allowed; other tools follow Claude Code's permission rules | Developer machines |
--claude-permission-mode plan | The agent plans and changes nothing | Reviews, dry runs | |
--claude-permission-mode bypassPermissions | Any command, without asking | Only in a disposable container or VM | |
--claude-settings | Extra Claude Code settings, such as sandbox and network rules | Allow the SAT API host, deny everything else you can | |
--codex-sandbox read-only | No writes | Reviews | |
--codex-sandbox workspace-write | Yes | Writes inside the workspace | Developer machines |
--codex-sandbox danger-full-access | No sandbox | Only in a disposable container or VM | |
--max-turns | Caps Claude Code turns per run | Bound the cost and blast radius of one run |
If the agent's sandbox blocks network access, the agent cannot reach the SAT API and its sat commands fail. Allow the API host through --claude-settings rather than switching to an unrestricted mode.
Secrets hygiene
- Never put secrets in tasks, comments or agent instructions. They are sent to the model provider in the prompt and stored in SAT, visible to every member.
- Transcripts store tool output. A command that prints a secret puts it in the run transcript, which every member can read. Keep secrets out of files and environment variables the agent is likely to print.
- Protect the key at rest. Use
sat apikey create --store(the macOS Keychain or libsecret when available, otherwisecredentials.jsonwith mode 0600), or an environment file with mode 0600. Never pass a key as a command-line argument on a shared machine. - Prefer expiring keys (
--expires-in-days) and rotate them. Revoke a key as soon as a runner machine is retired or compromised. - One key per runner. Name keys after the machine (
grace-laptop-runner,ci-runner) so you can revoke one without stopping the others.
Recommendations for production
Recommendations
The items below are recommendations, not behaviour SAT enforces.
- Run agents on a separate machine or container. Use a VM, container or CI job with nothing on it except the agent CLI, git and the runner. Treat it as untrusted. This is the only real boundary while agents share the runner's user and environment.
- Use a dedicated account. Run the runner as its own OS user with no access to personal files. When the API supports adding members, use a separate SAT member account for runners rather than an owner's key.
- Give least privilege outside SAT.
- Git: read-only deploy keys or tokens if agents should not push; a bot account with branch protection if they should.
- Model providers: a dedicated provider key with its own spending limit.
- Cloud: no ambient credentials in the runner's environment.
- Network: restrict outbound traffic to the SAT API, the model provider and your git host.
- Start the environment clean. Launch the runner from a service definition with only the variables it needs (see Run as a service), not from your interactive shell.
- Keep sandboxes on. Use
acceptEditsorworkspace-write. ReservebypassPermissionsanddanger-full-accessfor disposable environments. - Bound spend. Set every agent's
monthly_budget_centsand decide budget overrides yourself. Agents can approve their own, so watch the activity log for approvals decided by the runner's key. - Review before merge. Keep
--on-success in_reviewand review thesat/...branches before anything reaches your main branch. - Clean up workspaces that hold copies of your code. See Clean up.