Skip to content

Trust & security

Nothing that changes what a future audit run does — a memory promotion, a skill proposal, a fleet-published skill, a promoted control, a superuser grant — happens without a human approving it. One rule, isHumanAdmin, guards thirteen admin write paths (approve_proposal, reject_proposal, add_memory(shared=true), promote_memory, promote_reference, the UI’s proposal-approve/reject endpoints, sync_put/sync_delete, promote_endpoint, and the four principal-management writes): isAdmin and no subagent claim on the token. This is the same gate described in the control gate tools and the learning loop, stated here as the security property it actually is — an agent cannot unilaterally make itself, or a later agent, more trusted.

In dev mode there’s no cryptographic identity to check, so the same rule becomes a truthfulness guardrail, not a security boundary: a session that names itself corral-agent at the MCP handshake, or that calls bootstrap/report_host (every shipped worker does; corral-admin never does), is marked a worker for that session’s life and refused at the same gates — workers propose, the operator disposes.

An agent can spawn an out-of-process subagent with a scoped, TTL-bound delegation token: the subagent acts under its own identity, accountability rolls up to the spawning principal, and the token dies on schedule (depth- and fan-out-capped). In-process subagents share their parent’s session and token, so they’re indistinguishable from the parent at the gate — the boundary is per-session, and out-of-process delegation is the spawn mode that actually matters for autonomous workers. This is a disclosed limitation, not a hidden gap: it’s why the human gate is described as per-session enforcement, not per-agent.

A read-only observer token, minted via mint_observer (or corral-admin mint-observer), grants view-only access to a brain’s live state. corral-observe uses exactly this token shape, and as defense in depth refuses non-GET methods locally even if handed a non-read-only token by mistake. Full write access is scoped to authenticated members and superusers via the brain’s own principal store, seeded day-0 from CORRALAI_ALLOWED_PRINCIPALS/CORRALAI_ADMIN_PRINCIPALS and canonical in the database after.

Agent-executed commands run inside a sandbox boundary (internal/sandbox) — a bwrap namespace jail on Linux, workspace-confined with secret-free env — rather than directly against the operator’s own filesystem. The demo’s CLOBBER=1 mode (see claims & leases) still runs inside this same sandbox; it only disables coordination claims, not the sandbox itself.

Before the brain pushes a mission’s branch and opens a pull request, it scans the cumulative changed files for problems the herd must not ship (internal/egress). Committed secrets — API keys, tokens, private-key blocks — are blocking: the push is withheld, a critical finding is filed, and the mission is parked until an operator intervenes. New or vulnerable dependencies and license conflicts are flagged as advisory findings. This is the last brain-side checkpoint before code leaves for any forge — the forge-agnostic floor beneath GitHub’s own secret scanning, which self-hosted Gitea and GitLab don’t get. Containment runs both ways: the jail bounds what an agent can do; the egress scan vets what it can ship.

Corralai coordinates agents and enforces process gates — it does not itself guarantee the correctness of any given agent’s code, model output, or judgment. The verify gate, findings, and human review exist because of that limit, not instead of it.