Agent Office v0.2.3 · POC Get started
Menu: Security

Security

Threat model

What Agent Office protects, from whom, and which mechanism is responsible for each defence.

What we protect#

AssetWhere it livesWhy it matters
Root credentialsEncrypted secret store in the state directory (AES-256-GCM, key file alongside, both 0600): forge admin token, model credentials, agent forge passwords, session and webhook secrets, and with the bundled Gitea its admin passwordWhoever holds them can act as the office
The audit recordLedger in the office database, transcripts in the state directory, anchors in the policy repoIt's how you answer "who did what"
PolicyThe policy repo's mainIt decides who exists and what they may do
Each agent's memoryIts vault repoAn agent's instructions and knowledge
Company reposYour forgeThe actual work product
SpendModel credential (API key or subscription token)Money

Who we defend against#

A misbehaving or manipulated agent#

This is the main threat. An agent can make mistakes, or be steered by something it reads: a mail, a file, a web page within its egress list (prompt injection). We assume it may try anything its shell allows.

It tries toStopped by
Grant itself a capabilityRing 1. Policy changes need a human merge. hr_propose_change only opens a PR, and a capability window needs a human's approval.
Rewrite its own instructions (CLAUDE.md)Ring 2. Protected file patterns on the vault's main (verify check 3).
Read the ledger, transcripts or secretsRing 3. Separate OS user, state directory is 0700 (verify check 1).
Edit the ledger to hide what it didThe ledger is written only by the office, and the hash chain and anchors make edits detectable (verify check 6).
Read or write another agent's vaultRing 3 on disk (check 2), ring 2 on the forge (check 4).
Send data to an outside hostRing 3 strict network allowlist (check 7), and ring 4 deny rules on WebSearch, and on WebFetch, curl and wget unless it has net.egress.
Keep using a token after the runThe forge token is revoked at the end of every run, and the office MCP token only works while the run is running.
Use an MCP server the office didn't give it, or add rules through a settings file in its vaultRing 4. Only the office MCP server, with --strict-mcp-config; no user or project settings are loaded.
Spend without limitWith hard_stop: true (the default), admission refuses runs once today's spend reaches budget.usd_per_day, and each run gets the remaining budget as --max-budget-usd. Each run is also capped by max_turns and timeout_minutes.
Mail someone it shouldn'tmail_send checks the mail.send recipient list server-side, and denials are ledgered.
Keep two agents waking each other foreverThe mail loop guard: beyond 3 automatic reply hops, a reply is delivered without starting a run (mail.loop_guard).

A human with limited access#

Every route and human MCP tool declares one permission. A viewer can't chat, an operator can't read transcripts, and only admins read the ledger. A department lead's role covers only that department's agents. Connecting Claude through the human MCP gives it exactly the connecting human's access.

Someone on the network#

  • Forge webhooks are verified with an HMAC-SHA256 signature (X-Gitea-Signature) over the raw body, keyed with the webhook.secret. An unsigned or wrongly signed webhook is rejected (401) and does nothing.
  • MCP endpoints need a bearer token. Agent tokens are per run, stored hashed and valid only while their run is running. Human tokens are stored hashed, shown once and can be revoked; a disabled human's tokens stop working.
  • The office server listens on 127.0.0.1; officectl install writes a Caddy site that serves it over HTTPS (Caddy's automatic TLS). Web forms carry a CSRF token.

A compromised office host#

Out of scope for v0.2. The office process holds the forge admin token and the model credentials, and runs agents through sudo. Anyone who controls the office's OS user, or root, controls the office. See limits.

Design rules that follow#

  • Agents propose; deterministic checks decide. No permission decision is made by a model, including the Agent Resources agent.
  • Fail closed. No sandbox, no run. No model credential, run refused. An agent that isn't hired, or isn't known, gets no runs.
  • Record from outside. Events are recorded by the supervisor reading the harness's output stream, and by the office MCP server, not reported by the agent.
  • Never log secrets. Token mints and revocations are ledgered without values, and no secret goes on a command line (argv is readable by every user through ps).