For the complete documentation index, see llms.txt. This page is also available as Markdown.

Security

The agent's security model: bearer auth, HMAC webhooks, secret handling and rotation, callback allowlists, and network posture.

Context — Everything security-relevant about running an agent, in one place: who can call what, how each credential flows, and what to lock down. Assumes the network surface overview.

Authentication surfaces

Inbound: bearer token (everything except health, webhooks & login)

All API routes except the health probes, /webhooks/*, and the /auth/login flow require:

Authorization: Bearer <agent api key>

The token is the manifest's runtime.api_key (resolved from ${AGENT_API_KEY} or your chosen variable). Comparison is constant-time.

For the built-in chat UI only, the same key can be presented as an HttpOnly agent_auth cookie, set by typing the key into POST /auth/login (browsers can't attach bearer headers to the UI's own requests) and cleared by POST /auth/logout. The cookie carries the same secret with the same powers — everything below applies to it equally.

Properties to design around:

  • One shared token per agent. There is no per-client identity, no scopes, no expiry. Anyone holding the token has the full API: read any session, post messages, trigger autonomous routines.

  • Therefore: the token belongs to your integration tier only. Browsers and end-user devices must never see it — your integration authenticates end users its own way and holds the agent token server-side (the SDK guide's architecture).

  • Treat it like a database password: secret store, rotation procedure, never in URLs or logs.

Inbound: HMAC signatures (/webhooks/*)

Third-party webhook entry points bypass bearer auth — the provider's signature over the raw body is the authentication:

  • Signature = prefix + hex(HMAC(secret, raw_body)), algorithm sha256 (or sha1/sha512 where a provider requires it), carried in the configured header. Verified constant-time; any failure → 401 with no detail.

  • Unknown webhook names and routines without webhook config return an identical 404 — the public surface doesn't reveal what exists.

  • Rotation without restart: the secret env var is re-read on every request. Update the secret in the platform's secret store and both old and new traffic windows behave predictably (one secret is valid at a time — coordinate the provider-side switch).

  • Replay safety: identical deliveries dedupe to the same run via a body-hash idempotency key — a replayed webhook cannot double-fire a routine.

Outbound credentials

Destination
Credential
Header

LLM router

llms.api_key

Bearer

InteractiveAI platform (boot fetch)

interactive_platform.{public_key,secret_key}

platform auth

MCP servers

per-server mcps[].api_key

Bearer

Knowledge base (pgvector)

search.password

Postgres auth

External search

search.api_key

Bearer

Traces backend

traces.backend.api_key

Bearer or Basic (api_key_scheme)

Autonomous callbacks & event webhooks to your integration

the agent api key

Bearer

Your callback/webhook receivers must verify that bearer header — otherwise anyone who can reach them can forge "agent results".

Secret handling rules

The manifest cannot contain a secret value — credential fields only accept ${VAR_NAME} references, enforced by schema validation:

  • Resolution at boot, fail-fast: missing variables abort startup with the variable name. No fallback path, no partial boots.

  • Exception — webhook secrets are read per request (rotation support, above).

  • You declare a secret bundle in the manifest's secrets: list (by its name in Interactive Secrets); the platform injects that bundle's key/value pairs as environment variables before boot. The value exists only in the agent's environment, never in the manifest.

  • Rotation procedure (all except webhook secrets): update the secret in the platform's secret store; the platform rolls the agent to pick it up. The old credential must stay valid until the rollout completes.

  • Logs and config dumps redact credential fields; Postgres URIs are logged with credentials masked.

Autonomous-surface hardening

  • callback_url_allowlist on every autonomous routine in production. Without it, any caller holding the bearer token can point results at any URL. With it, only listed hostnames (a leading . allows the apex and subdomains) receive callbacks.

  • Operator timeout bounds are a backstop against runaway runs: a routine's timeout_seconds is capped by AUTONOMOUS_MAX_TIMEOUT_SECONDS (default 600s) regardless of what the YAML asks for.

  • Input schemas are a security control — strict input_schemas reject malformed payloads at the door (HTTP 400), before any model sees them.

Prompt-level exposure

What reaches the model is what's in the session: messages, tool results, variables, retrieved snippets. Practical consequences:

  • Anything a tool returns can end up in a reply. Don't return fields the customer must never see; filter server-side in the MCP tool, not in instructions.

  • Injected tool events (/sessions/{id}/tool_events) render verbatim into prompts (control characters are stripped). The endpoint is bearer-gated, but treat injected payloads with the same trust you'd give tool results.

  • Variables are agent-visible by definition — never put secrets in variables. Integration-private data goes in metadata, which never reaches a prompt.

  • Traces capture conversations, tool results, and variables and the trace metadata snapshot is not redacted. Apply access control on the traces backend accordingly, and point traces.backend at your own collector if platform-default storage doesn't meet your data policy.

Network posture checklist

Last updated

Was this helpful?