Security infrastructure
Short-lived credential leases for runs, one outbound door with a per-factory egress policy, content scanning of uploads and artifacts, and a dependency gate on agent pull requests.
CodeBook does not run repository code on its own servers. Agents read and write through the git provider's API, MCP tool connections are HTTP only, and outside runtimes are HTTP adapters. So "sandbox" in CodeBook means controlling what a run can reach and which credentials it can use, and it is enforced in four places, none of them a prompt. There is no process sandbox, because there is no process to put in one.
Open Factory settings → Security for the egress policy and its rules, one-click Allow for hosts the factory's own configuration reaches, the dependency gate, scanner status, the credential leases runs currently hold with a Revoke button, and recent refusals.
Credential leases
A run never holds a stored credential. It gets a lease bound to the job, the purpose (git provider, MCP server or runtime secret), the credential row and one host, with a two-minute lifetime. The credential is decrypted for one request at a time; no row and no response carries the secret.
The dispatcher's heartbeat renews leases while the job is running. They are revoked when the job ends by any path, when a person cancels the job, by the kill switch and by Emergency revoke, which now reports the leases it revoked. A run whose lease was revoked never gets another one.
Refused, and recorded as a security refusal and a secret_refused run event: a request to another host, an expired lease, a revoked lease, or a job that is no longer live.
Leases cover the run engine's repository use, MCP tool calls, webhook signing secrets and Devin keys during a run and while polling, and GitHub Actions dispatch and polling. A person's own actions — settings, testing a runtime, chat — use the stored credential directly.
The lease is short-lived. The underlying credentials are not: CodeBook authenticates to GitHub and GitLab with personal access tokens, not a GitHub App, so there is no installation token to mint. Board webhook signing secrets are stored in plain text today, and the MadeBook governance credential is CodeBook's own control-plane credential rather than a per-run one; neither goes through the broker.
One outbound door
Every request a run can cause — the git provider, MCP servers, webhook and Devin runtimes, event deliveries, board webhooks and the vulnerability database — goes through one seam. In order: http(s) only with no credentials in the URL; the factory's policy; DNS resolved and every private, loopback, link-local, CGNAT and metadata address refused; redirects followed only within the same origin, at most three, and not at all for webhooks; a timeout and a body size cap. A test reads the service files and fails if one of them calls fetch directly.
A factory with no policy is open: any public host, as before. The private-network refusal is always on. A factory can switch to allowlist, in which anything not listed is refused. A deny rule wins in either mode. An unreadable policy refuses the request. A refusal is recorded, and inside a run it is also an egress_refused run event.
Not covered: platform calls to SSO for AI, mail and files, which go to the operator-configured origin rather than anywhere a run chooses. The connection is not pinned to the resolved address, so a DNS-rebinding race between resolution and connection is not closed; the web knowledge fetch does pin, because it has its own transport.
Content scanning
Chat uploads, agent exports and artifact text are sniffed by their magic bytes. Refused: executables, archives, anything that is not text, and text carrying a base64-encoded executable or archive.
A malware scanner is used when the deployment sets CLAMD_HOST (and CLAMD_PORT, default 3310), through ClamAV's clamd streaming protocol. With no scanner configured the verdict is not_scanned, never clean. If a scanner is configured and errors, the content is refused.
The card's Security checks section shows the content verdict of each of its artifacts.
Dependency scanning and the gate
After an agent or crew opens a pull request, each changed lockfile is parsed from the exact content committed and diffed against the base branch. Supported: npm package-lock/npm-shrinkwrap, yarn.lock (v1 and Berry), pnpm-lock (v5, 6 and 9), requirements.txt with exact pins, poetry.lock, go.sum, Cargo.lock and Gemfile.lock. Only added or changed versions are sent to OSV.dev, and each finding's severity comes from the advisory, otherwise from a CVSS v3 base score computed from its vector, otherwise unknown.
Findings are rows on the card, linked to osv.dev, and the agent is told the result in its tool output.
The factory's dependency gate is off, high or critical. It is checked when a worker passes, right after the station contract check. When it trips, the worker's pass is recorded as blocked with a policy failure code, the same way a failed contract is. Unknown severity counts as high, and a scan that errored also blocks. The newest scan of each pull request is the one that counts. A person's approval is not held to the gate.
A base-branch lockfile over the provider's 1 MB contents limit is read as absent, so every version in it is checked: over-reporting rather than under-reporting. package.json ranges are not resolved to versions.