← Docs

Security model

Trust tiers, per-member tokens, quarantined writes, the append-only audit log, and the bind rules that keep a federation off the open internet by default.

Bourdon federates the memory of every agent you run. That is its value and its blast radius: a single compromised member that can read everything exfiltrates everything. The model below replaces "everyone who reaches the server is equal" with explicit, server-side trust, and every control on this page is covered by negative tests in CI.

Threat model#

ThreatDefence
Anyone who finds the endpoint reads your federationNo anonymous path on a network-reachable bind: loopback-only default, startup refusal without auth, bearer auth on every request.
A compromised member exfiltrates every agent's memoryTrust tiers. Quarantined members read only namespaces they were granted, deny by default.
A poisoned member injects content that propagates to every agentQuarantined writes are staged and invisible to all reads until an operator promotes them. Members write only their own namespace.
A member is compromised mid-incidentbourdon revoke <member>: token dead on the next request, no restart.
"What did it touch?"Append-only audit log of every operation, allow and deny, queryable per member, surviving revocation.
Token theft from disk or logsTokens are stored as SHA-256 hashes only, compared in constant time, shown once at creation, never logged.
A request arrives under a hostname you never served421 Misdirected Request before authentication unless the name was declared.

Out of scope today, and said so: multi-tenant federation, encryption at rest, per-memory-item ACLs.

Identities and tokens#

Every federation member is registered in ~/.bourdon/federation.yaml:

bourdon agent add openclaw                        # quarantined by default
bourdon agent add local-assistant --tier trusted  # an agent you control
bourdon agent list                                # never shows token material
bourdon agent rotate openclaw                     # new token, old one dead
bourdon revoke openclaw                           # effective now

agent add prints the bearer token once. Bourdon keeps only the hash. On the HTTP transport the member presents Authorization: Bearer <token> and the server resolves it to an identity: agent id, tier, grants.

Two transports, two identity rules:

  • stdio: the caller is your own process, so it gets the implicit trusted operator identity.
  • HTTP: a bearer token is required.

Tiers#

trustedquarantined
Readeverything, visibility-filteredonly granted namespaces; deny by default
Read surfaceall tools and resourcesquery_agent_memory, find_entity, list_recent_work, list_agents, export_agents, plus version history for granted namespaces. Aggregate tools (prepare_recognition_context, get_deeper_context, get_cross_agent_summary, compile_codex_turn) are denied outright.
Write (commit_to_federation)direct to the live storestaged under staging/<member>/, own namespace only
rollback_agent_memoryallowed, snapshotted firstnever, by any route
Default for new membersyes

A namespace is one agent's manifest. Grant and remove reads with:

bourdon grant openclaw claude-code      # openclaw may now read claude-code's manifest
bourdon ungrant openclaw claude-code

Enforcement is server-side at the request layer. An adapter cannot bypass it, and trusted agents implement no security logic client-side.

Staging#

bourdon staging list
bourdon staging promote openclaw   # merge into the live store, same validated path as a trusted write
bourdon staging reject openclaw    # delete without promoting

Staged manifests live outside the agents/ directory, so they are invisible to every read tool, every peer, and the desktop tray until promoted. Quarantine follows the content: an operator-run export of a quarantined-class adapter also stages.

Audit#

Every federation operation, allowed or denied, on every transport, appends one line to ~/.bourdon/audit.jsonl:

bourdon audit                       # recent operations
bourdon audit --agent openclaw      # one member's trail, survives revocation
bourdon audit --denials             # what was blocked
bourdon audit --export              # raw JSONL for your own tooling

No token material is ever written to the audit log or any other log.

Provenance and undo#

Every write archives the manifest it replaced. list_memory_versions shows the history for a namespace, explain_memory_change returns the write that produced a given state (caller identity is recorded and verified; the session and transcript references a caller attaches are not), and rollback_agent_memory restores an archived version. Rollback is the most destructive operation the server exposes: it discards every later contribution, including other agents', so it is trusted-only, it accepts an expected_digest to refuse if anything landed meanwhile, and the restore is itself snapshotted.

Bind and startup contract#

  • Default HTTP bind is 127.0.0.1.
  • A non-loopback bind requires configured auth (a registered member or the legacy shared token). Without it the server exits non-zero at startup.
  • --allow-unauthenticated is honoured on loopback only; combined with a non-loopback host the server refuses to start.
  • Remote peers must be HTTPS; plaintext HTTP is loopback-only.
  • Every public name must be declared with --allowed-host; undeclared Host headers get 421.

What the manifests themselves leak#

Tokens are one risk; memory content is another. Every participant applies visibility before a row is emitted, private rows never leave the machine, and bourdon audit-leaks --strict --require-files scans the published manifests for credential shapes and escaped private rows. That scan runs against a real on-disk fixture in CI so it can never pass by scanning zero files.

Verification#

bourdon doctor reports federation hygiene: auth posture, members with missing or invalid tiers, revoked-but-present tokens, and staged writes older than seven days. The design rationale behind all of this is spec/SPEC_v0.9.0.md; vulnerability reporting is in SECURITY.md.