Skip to content

Threat Model ​

This document enumerates the attacks that Kanoniv Agent Auth is designed to resist, the specific mechanisms that prevent each attack, and the residual risks that remain.

Attacker Model ​

We assume an attacker who can:

  • Observe all network traffic between agents and servers (passive MitM)
  • Inject or modify messages in transit (active MitM)
  • Compromise one or more intermediate agents in a delegation chain
  • Gain write access to the provenance store
  • Craft arbitrary JSON payloads and submit them to MCP servers

We assume an attacker who cannot:

  • Obtain an agent's Ed25519 private key without compromising that agent's runtime
  • Break Ed25519 signatures (requires 2^128 operations)
  • Break SHA-256 collision resistance (birthday bound at 2^128)

Attacks and Mitigations ​

1. Agent Impersonation ​

Attack: An attacker claims to be Agent A by using Agent A's DID in a signed message or delegation.

Mitigation: Every signed message includes an Ed25519 signature over canonical bytes. Verification recomputes the canonical form from {nonce, payload, signer_did, timestamp} and checks the signature against the claimed signer's public key. Without Agent A's private key, the attacker cannot produce a valid signature for Agent A's DID.

Verification code path: SignedMessage::verify() checks that self.signer_did == identity.did, then verifies the Ed25519 signature over the canonical bytes using the identity's public key.

2. Privilege Escalation via Delegation Tampering ​

Attack: Agent B receives a delegation with action_scope: ["resolve"]. Agent B modifies the outer caveats field to ["resolve", "merge", "split"] before delegating to Agent C.

Mitigation: During verification, caveats are extracted from the signed payload (delegation.proof.payload["caveats"]), not from the outer delegation.caveats field. The signed payload is immutable - any modification invalidates the signature. The outer field is ignored for authorization decisions.

Test: test_tampered_delegation_caveats_detected - modifies outer caveats to widen scope, verifies that the invocation is still blocked by the original signed caveats.

3. Delegation Chain Forgery ​

Attack: Agent C constructs a fake delegation chain claiming Root -> B -> C, without B's involvement.

Mitigation: Each delegation embeds the issuer's public key (issuer_public_key field) and is signed by the issuer. Verification:

  1. Reconstructs the issuer identity from the embedded public key
  2. Checks that the reconstructed DID matches issuer_did
  3. Verifies the delegation signature using the reconstructed identity
  4. Checks that parent.delegate_did == current.issuer_did (chain linkage)

Without B's private key, C cannot produce a valid signature for B's DID. The embedded public key prevents substitution because the DID is derived from SHA-256(public_key)[0..16] - a different key produces a different DID.

4. Replay Attacks ​

Attack: An attacker captures a valid signed message and replays it to perform the same action again.

Mitigation: Every SignedMessage includes a UUID v4 nonce field that is part of the signed canonical bytes. Verifiers MAY maintain a nonce registry and reject previously-seen nonces. The timestamp field (also signed) enables time-window-based replay rejection.

Residual risk: Replay protection requires the verifier to maintain state (a nonce set or time window). The protocol provides the nonce; enforcement is application-specific. A stateless verifier that does not track nonces is vulnerable to replay within the delegation's validity period.

5. Man-in-the-Middle ​

Attack: An attacker intercepts an MCP tool call, modifies the arguments (e.g., changes entity_id), and forwards the modified request to the server.

Mitigation: The invocation's proof field contains an Ed25519 signature over {invoker_did, action, args, delegation_hash}. Modifying any argument changes the signed payload, invalidating the signature. The server verifies the invocation signature before processing.

Note: The invocation signs the args that were provided at invocation time. If the MCP tool call's top-level arguments differ from the signed args, the server detects tampering during proof extraction.

6. Compromised Intermediate Agent ​

Attack: Agent B (in chain Root -> B -> C) is compromised. The attacker uses B's key to issue new delegations to arbitrary agents with wider scope.

Mitigation: Three mechanisms limit the damage:

  1. Caveat accumulation. B cannot issue delegations with fewer caveats than it received. Any delegation from B carries Root's caveats plus any additional restrictions B adds. The attacker cannot use B to grant merge authority if Root only granted resolve.

  2. Independent signature verification. Every delegation in the chain is independently verified. Compromising B does not give the attacker the ability to forge Root's signature. The chain must trace back to a valid Root signature.

  3. Revocation. The verify_invocation_with_revocation function accepts an is_revoked callback. When B is known to be compromised, revoke B's delegation by content hash. All downstream delegations (B -> C, B -> D, etc.) become invalid because the chain walks through B's revoked delegation.

Residual risk: Between compromise and revocation, B can issue new delegations within its authorized scope.

7. DoS via Deep Delegation Chains ​

Attack: An attacker constructs a delegation chain of depth 10,000 and submits it for verification, consuming excessive CPU time walking the chain.

Mitigation: Hard limit of MAX_CHAIN_DEPTH = 32. Both creation and verification enforce this limit. Delegation::create_inner checks parent.depth() >= MAX_CHAIN_DEPTH before creating a new delegation. verify_invocation_with_revocation tracks steps and returns DelegationChainBroken when the limit is exceeded.

32 levels is sufficient for practical delegation hierarchies (organization -> team -> agent -> sub-agent) while preventing unbounded computation.

8. DID Collision ​

Attack: An attacker generates many keypairs to find one whose DID matches a target agent's DID (second-preimage attack).

Mitigation: The DID uses 128 bits of SHA-256 output (SHA-256(public_key)[0..16]). Finding a second preimage requires approximately 2^128 operations. For birthday-bound collisions (finding any two DIDs that collide), the bound is approximately 2^64 identities.

Residual risk: At 2^64 identities (~1.8 x 10^19), collision probability becomes non-negligible. This is adequate for practical agent populations. If a system manages more than 2^40 (~10^12) agents, the collision probability is still below 2^-48.

9. Provenance Entry Tampering ​

Attack: An attacker with write access to the provenance store modifies a historical entry (e.g., changes action: merge to action: resolve or modifies entity_ids).

Mitigation: ProvenanceEntry::verify() performs two checks:

  1. Verifies the Ed25519 signature on the signed_envelope
  2. Compares every outer field (agent_did, action, entity_ids, parent_ids, metadata) against the corresponding field in the signed payload

Modifying any outer field without re-signing produces an IntegrityMismatch error. Re-signing requires the original agent's private key.

DAG integrity: Entries reference parents by content hash (SHA-256 of the canonicalized signed message). Modifying a parent entry changes its content hash, breaking all references from child entries. An attacker would need to re-sign the entire subgraph downstream of the tampered entry.

10. Embedded Public Key Substitution ​

Attack: Agent C modifies a delegation's issuer_public_key to substitute a different key (one C controls), then forges a new signature using that key.

Mitigation: Verification reconstructs the DID from the embedded public key and checks it against issuer_did. Since the DID is SHA-256(public_key)[0..16], a different public key produces a different DID. The check issuer_identity.did != current.issuer_did catches the substitution.

11. Root Key Compromise ​

Attack: The root authority's private key is stolen.

Mitigation: This is the highest-severity failure. All delegations signed by the root are now suspect. Recovery requires:

  1. Revoking all delegations issued by the compromised root (via the is_revoked callback)
  2. Generating a new root keypair (new DID)
  3. Re-issuing all delegations from the new root

Residual risk: Between compromise and detection, the attacker can issue arbitrary delegations as the root authority. There is no key rotation mechanism within the DID - the DID is permanently bound to the key. This is a deliberate design choice: in-protocol key rotation adds complexity and its own attack surface (key rotation hijacking).

Out of Scope ​

The following are explicitly not addressed by the cryptographic protocol:

  • Confidentiality. Messages are signed, not encrypted. An observer can read payloads. Use TLS for transport confidentiality.
  • Availability. The protocol does not prevent denial-of-service at the network layer. The depth limit prevents algorithmic DoS only.
  • Key storage. How private keys are stored at rest (HSM, encrypted file, environment variable) is the deployer's responsibility. The protocol specifies the key format (32-byte Ed25519 secret), not the storage mechanism.
  • Semantic authorization. Caveats constrain actions and resources syntactically. Whether resolve on entity:customer:123 is semantically appropriate for a given business context is application logic, not protocol logic.

The identity and delegation layer for AI agents.