Structural security over permission scoping
Most platforms answer “what if the agent is compromised?” with narrower permissions: scope the token, shorten its life, restrict its audience. Scoping helps, but it encodes an assumption about what a compromised agent can’t do — and that assumption goes stale as models get more capable. Checkfu’s design law says the stronger thing:What must not leak is structurally absent, never merely denied.A raw provider secret is never present in the sandbox, the event log, model context, or harness configuration. There is no vault the agent can query, no environment variable to read, no proxy that substitutes
$SECRET_NAME into outbound traffic. When a control
fails, the failure mode is a denied action — never a disclosed secret.
What this means concretely
Credentials attach after the agent’s involvement ends. A Connection’s provider credential is held in the selected custody boundary, behind an opaque handle. When a harness calls a credentialed tool, Checkfu compiles the outbound request server-side and that boundary attaches the secret at its outbound edge, outside the sandbox. The agent’s process never holds a secret it could exfiltrate — this is what “credential-free” means on every page of these docs. See Connections and catalog for the object model behind that split. There are two custody modes. Native accounts (D215) seal the record in Checkfu’s own store, addressed by the custody binding rather than by Workspace; authenticated encryption binds it to that exact address, so a record moved between namespaces, integrations, or handles fails to open. Checkfu also owns that outbound call: the client refuses to follow redirects in code, and the worker is configured to reach public destinations only — a pairing proved for every worker configuration rather than asserted. Runtime-backed accounts keep encrypted records and refresh machinery inside the selected IntegrationRuntime adapter; credential bytes may cross only that trusted adapter and its provider request edge. What did not change in either mode is the claim this page is about — no API response, event, log, sandbox, or model context can read the credential back. Mounts carry no secrets. The runtime handoff that gives a sandbox its Project trees and memory directories is a credential-free mount plan: file bodies are resolved by the platform against the Session’s own lease, never by shipping a token into the sandbox for the agent to use. The network boundary is declared before any credential exists. Every Connection carries between 1 and 32 default-deny egress rules — host, port, path prefix, methods, and a default-deny header allowlist — declared at authorization time. A request that matches no rule is not sent, and routing- and authorization-bearing headers are denylisted so a tool call cannot smuggle a credential or redirect itself. A SandboxProfile’s network policy is a different boundary, and a weaker one. Connection egress rules are enforced where Checkfu makes the request, outside the sandbox, so a hijacked workload cannot get around them. A SandboxProfile’s ownnetwork_policy constrains traffic the workload itself originates, and that is enforced by
a filter running alongside the workload. No provider Checkfu ships today grades it above
advisory_filter: it stops a confused agent, not a determined one. An allowlist policy
may demand the stronger grade with required_egress_certification: "security_boundary",
and admission then refuses any provider whose exact revision does not advertise it — which,
until a certified provider revision exists, means such a SandboxProfile is refused outright rather
than quietly downgraded. Until then, treat workload-originated egress as unenforced when
you decide what data may enter a sandbox.
An allowlist policy has conveniences, and they are abbreviations rather than modes.
allow_package_managers and allow_mcp_servers are CMA’s flag names, adopted so a
migrating config is copy-paste, but a flag never becomes a standing allowance: at
admission it compiles into the SandboxProfile revision’s allowed_hosts, and enforcement,
the conformance tuple, and the Runner’s own compile see exact hosts only. Three
consequences follow. The expansion is readable — a GET on the SandboxProfile shows every host
the flag granted, so there is no second, invisible allowance to audit. It is pinned — a
published version froze the hosts the preset catalog held at publication and records the
catalog version that produced them, so editing the catalog cannot reach a SandboxProfile that
already exists. And adopting a newer catalog is therefore a publish: a new SandboxProfile
version, a new derived image digest, a new network-policy hash. A preset update is a
policy change you can see and refuse, which is what “never a silent widening” has to
mean. allow_package_managers expands to the public registries for exactly the six
package ecosystems a SandboxProfile can declare; allow_mcp_servers deliberately expands to
no workload host at all, because a Checkfu sandbox never dials an MCP server itself —
every MCP call crosses the CapabilityGateway at plane authority, so adding third-party MCP
hostnames to the workload set would be a real grant wearing parity’s clothes. The
practical consequence is worth knowing before you port a config: an allowlist has to
name somewhere to reach, so allow_mcp_servers on its own, with no hand-written
hosts and no allow_package_managers, is refused at admission rather than admitted as
an allowlist that reaches nothing.
Customer code never enters the trusted plane. Checkfu’s Runner is data-plane
infrastructure, not workload code. Your harness, shims, install hooks, and
dependencies execute inside the sandbox under the workload threat model; the Runner
never dynamically imports customer code. Isolation strength is a property of who
authored the workload, not of a deployment stage or nominal sandbox tier. D243 fixes
the server-owned fact as trusted | adversarial, defaults missing provenance to
adversarial, and requires every realized enforcement axis plus either no network or
certified allowlist egress for that lane. A trusted Session may not later acquire
third-party executable content or steering; that requires a new adversarial Session.
Agent Versions and Session admission now freeze this classification, but concrete
provider placement does not yet enforce it (V-SBX-017). The complete frozen admission is
deployment-key authenticated, while public Session events omit private declaration actor/role
provenance. Current hosted support
must therefore not be read as proof that workload trust is enforced.
The event log is the audit surface. Every Session is an append-only event log —
tool calls, approvals, denials, and settlements are readable after the fact in order,
and retention is a property of
every stored entity, including zero-data-retention Workspaces where execution content
never reaches a durable sink.
What scoping still does
Structural absence does not replace governance — it bounds what governance failures can cost. PermissionAssignments still decide what a permitted agent may do; policies still route sensitive actions through ActionApprovals; egress rules still shrink where a call may go. The law only insists that none of these is the mechanism keeping a secret safe from a hijacked workload. Scoping decides blast radius for permitted actions; structure guarantees the unpermitted ones fail without disclosure.The engineering-facing threat model behind this page — asset-by-asset blast radius,
sandbox tier rules, and what remains under analysis — lives in the repository’s
SECURITY.md. This page states only what that document supports.