Security Model
Kanoniv Agent Auth provides cryptographic identity and authorization for AI agents. The security model is built on five composable layers, each addressing a distinct class of attack.
The Five Layers
1. Cryptographic Identity (Ed25519 + did:agent:)
Every agent generates an Ed25519 keypair. The public key deterministically derives a did:agent: identifier via SHA-256(public_key)[0..16], hex-encoded. No registration server is required - the identity exists the moment the key is generated.
What it prevents: Identity spoofing. An agent's DID is bound to its private key. Without the private key, no valid signature can be produced for that DID. There is no central identity server to compromise.
2. Delegation with Attenuation
Authority flows through signed delegation chains. A root authority delegates to Agent A, who can delegate to Agent B, and so on. Each delegation carries caveats (constraints) that can only narrow the authority, never widen it. Caveats accumulate across the chain - if the root grants [resolve, search] and Agent A narrows to [resolve], Agent B can never search.
What it prevents: Privilege escalation. An intermediate agent cannot grant more authority than it received. Attempting to widen a delegation (e.g., adding merge when only resolve was granted) is structurally impossible because caveats are read from the signed payload during verification, not from mutable outer fields.
3. Tamper-Proof Caveats
Caveats are embedded in the signed delegation payload. During verification, the system reads caveats from the cryptographically signed inner payload, not from the outer (mutable) Delegation struct fields. Even if an attacker modifies the outer caveats array to add permissions, verification will enforce the original signed constraints.
Six caveat types are supported:
| Caveat | Constraint |
|---|---|
action_scope | Restrict to specific actions (e.g., ["resolve", "search"]) |
expires_at | Time-bound delegation (RFC 3339 timestamp) |
max_cost | Cost ceiling for the operation |
resource | Glob-pattern resource restriction (e.g., entity:customer:*) |
context | Key-value context binding (e.g., session_id: "abc") |
custom | Arbitrary application-defined constraint |
What it prevents: Tampering with authorization scope. Modifying delegation fields after signing is detected because the signed payload is the source of truth.
4. Fail-Closed Verification
The verification algorithm is fail-closed at every step:
- Missing delegation chain link -> reject
- Invalid signature at any depth -> reject
- Embedded public key does not match claimed DID -> reject
- Chain does not terminate at expected root -> reject
- Any caveat violated -> reject
- Chain depth exceeds 32 -> reject
- Database error in revocation check -> reject (not silent pass-through)
There is no "soft fail" path. If any check cannot be positively confirmed, the invocation is denied.
What it prevents: Authorization bypass through partial verification. Systems that fail-open (allow on error) are vulnerable to crafted malformed inputs that trigger error paths. Fail-closed ensures that any ambiguity results in denial.
5. Signed Audit Trail (Provenance DAG)
Every agent action produces a ProvenanceEntry with a signed envelope containing the agent DID, action type, affected entity IDs, and metadata. Entries chain into a directed acyclic graph (DAG) via content hashes. Tampering with any field (action, entity_ids, metadata) after signing is detected by comparing outer fields against the signed payload.
What it prevents: Audit log tampering. An attacker who gains write access to the provenance store cannot modify historical entries without invalidating their signatures. The DAG structure means altering one entry invalidates all entries that reference it as a parent.
How the Layers Compose
The five layers form a complete trust chain:
- Identity establishes who each agent is (DID bound to keypair).
- Delegation establishes what each agent can do (caveats bound to signatures).
- Tamper-proof caveats ensure the "what" cannot be expanded after the fact.
- Fail-closed verification ensures no step in the chain can be skipped.
- Provenance records what each agent actually did, with cryptographic proof.
An agent making an MCP tool call attaches a self-contained proof (_proof field) containing the full invocation and delegation chain. The server extracts the proof, verifies every signature from invoker back to root, checks all caveats, and only then executes the tool. No external key resolver or database lookup is needed during verification.
Attack Surface Summary
| Attack | Layer | Mitigation |
|---|---|---|
| Agent impersonation | 1 | Ed25519 signatures - requires private key |
| Privilege escalation | 2, 3 | Caveat-only attenuation, signed payloads |
| Delegation tampering | 3 | Caveats read from signed payload, not outer fields |
| Replay attacks | 4 | UUID v4 nonce per signed message |
| Man-in-the-middle | 1, 4 | Ed25519 signatures over canonical bytes |
| Compromised intermediate | 2, 4 | Every signature in chain independently verified |
| DoS via deep chains | 4 | Hard limit of 32 delegation levels |
| Audit log falsification | 5 | Signed provenance entries with DAG chaining |
| Root key compromise | 1 | Revocation callback invalidates all downstream delegations |
Design Decisions
No key rotation in-protocol. The DID is permanently bound to the public key. Key rotation means creating a new DID and re-issuing delegations. This is intentional - it keeps the protocol stateless. Key rotation state machines add complexity and attack surface.
No global resolver. DID resolution is local. The public key is embedded in delegations and proofs. There is no registry, ledger, or network call during verification. This eliminates an entire class of network-dependent attacks and makes the system work offline.
Caveats accumulate, never cancel. When Agent B re-delegates to Agent C, the new delegation carries all of B's caveats plus any additional ones. There is no mechanism to remove a caveat from a parent delegation. This is a structural guarantee, not a policy decision.
