Skip to content

Per-agent keys bound to mandates, and a threat model - #2

Merged
angelraph merged 1 commit into
masterfrom
feature/agent-keys
Sep 21, 2026
Merged

angelraph merged 1 commit into
masterfrom
feature/agent-keys

Conversation

@angelraph

Copy link
Copy Markdown
Owner

Every agent used to share one API key and name itself in the request body, so any agent could act as any other and use any mandate.

Each agent now gets its own key bound to specific mandates, its identity comes from the key rather than the body, it can only read its own results, and keys can be rotated and revoked immediately. Only a hash is stored. The shared key still works unless CHARTER_REQUIRE_AGENT_KEYS=true.

A live run found a flaw the tests had missed: revoking the last agent dropped the server to open mode. Once any agent has been registered the API now stays closed, with tests at the service and API level.

docs/THREAT_MODEL.md lists what each control defends against and what it does not.

27 new tests (122 total). Verified live: identity from key, spoofing and wrong-mandate refused, cross-agent reads hidden, rotation and revocation immediate, and the full serve plus rogue-agent demo still works.

Until now every agent shared one API key and named itself in the request
body, so any agent could act as any other and use any mandate.

- charter agent add / list / rotate / revoke. Each agent gets its own key,
  bound to specific mandates. The key is shown once; only its SHA-256 hash
  is recorded. Registry state is derived from the audit log.
- The agent's identity comes from its key, never the request body. A body
  naming a different agent is refused (403), as is a mandate the agent is
  not bound to.
- An agent reads only its own status and escalation results. Someone
  else's is reported as not found, so its existence is not revealed.
- Rotation replaces the key immediately. Revocation is immediate.
- The shared CHARTER_API_KEY still works; CHARTER_REQUIRE_AGENT_KEYS=true
  refuses it and accepts only registered agents.
- All credential comparisons are now constant-time.

A live run against the real server found a flaw the tests had not:
revoking the last agent dropped the server back to open mode, where
anyone could call it. Once any agent has been registered the API now
stays closed. Regression tests added at the service and API level.

docs/THREAT_MODEL.md lists what each control defends against and, as
plainly, what it does not. README trust-boundary section updated.

27 new tests (122 total).
@angelraph
angelraph merged commit 0febe42 into master Sep 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant