Agent-to-Agent Trust: Authentication, Delegation, and Capability Boundaries in Multi-Agent Systems

Agent-to-Agent Trust: Authentication, Delegation, and Capability Boundaries in Multi-Agent Systems

Problem

Multi-agent systems are moving from research demos to production deployments. A coordinator agent delegates tasks to specialist agents: one handles database queries, another manages deployments, a third writes code. Each agent has its own credentials, tools, and execution context. The security question that teams skip: how does Agent B verify that Agent A is who it claims to be, that A is authorized to make this request, and that A has not been compromised by prompt injection? Without identity verification between agents, a compromised agent can impersonate the coordinator and escalate privileges across the entire swarm. Without delegation boundaries, a low-privilege agent can ask a high-privilege agent to perform actions on its behalf, creating a privilege escalation chain. There are no established patterns for agent-to-agent authentication, and most multi-agent frameworks treat inter-agent communication as trusted by default.

Threat Model

  • Adversary: (1) Compromised agent (via prompt injection or supply chain attack) that attempts to manipulate other agents. (2) Attacker who gains access to the inter-agent communication channel and injects messages. (3) Legitimate agent that malfunctions and sends incorrect delegation requests at machine speed.
  • Blast radius: The union of all capabilities across all agents in the swarm. A compromised coordinator can weaponize every specialist agent. A compromised specialist with unrestricted delegation can request any action from any other agent.

Configuration

Agent Identity with mTLS

Every agent gets a unique identity backed by a TLS certificate. Inter-agent communication uses mutual TLS. No agent can communicate without presenting a valid certificate.

# agent-identity-cert.yaml
# cert-manager Certificate for agent identity.
# Each agent gets a unique certificate with its identity in the CN and SAN.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: agent-deployer-identity
  namespace: ai-agents
spec:
  secretName: agent-deployer-tls
  duration: 24h
  renewBefore: 8h
  subject:
    organizations:
      - "ai-agents"
  commonName: "agent-deployer"
  dnsNames:
    - "agent-deployer.ai-agents.svc.cluster.local"
  usages:
    - client auth
    - server auth
  issuerRef:
    name: agent-ca-issuer
    kind: ClusterIssuer
---
# CA issuer for agent certificates
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: agent-ca-issuer
spec:
  ca:
    secretName: agent-ca-keypair

Capability Tokens with Scope Limits

When Agent A delegates a task to Agent B, it issues a capability token that describes exactly what Agent B is allowed to do. The token is scoped, time-limited, and non-transferable.

# capability_token.py
# Issues and validates scoped capability tokens for agent-to-agent delegation.

import json
import time
import hmac
import hashlib
import base64

SECRET_KEY = b""  # Loaded from Vault at startup

def issue_capability_token(
    issuer_agent_id: str,
    target_agent_id: str,
    capabilities: list[str],
    resources: list[str],
    max_uses: int = 1,
    ttl_seconds: int = 300,
) -> str:
    """Issue a scoped capability token for delegation."""
    payload = {
        "iss": issuer_agent_id,
        "sub": target_agent_id,
        "cap": capabilities,       # e.g. ["read_file", "query_database"]
        "res": resources,           # e.g. ["/data/reports/*"]
        "max_uses": max_uses,
        "iat": int(time.time()),
        "exp": int(time.time()) + ttl_seconds,
        "delegatable": False,       # Cannot be passed to another agent
    }
    payload_bytes = json.dumps(payload, sort_keys=True).encode()
    signature = hmac.new(SECRET_KEY, payload_bytes, hashlib.sha256).hexdigest()
    token_data = base64.urlsafe_b64encode(payload_bytes).decode()
    return f"{token_data}.{signature}"


def validate_capability_token(
    token: str,
    presenting_agent_id: str,
    requested_capability: str,
    requested_resource: str,
) -> dict:
    """Validate a capability token. Returns payload if valid, raises on failure."""
    parts = token.split(".")
    if len(parts) != 2:
        raise ValueError("Malformed token")

    payload_bytes = base64.urlsafe_b64decode(parts[0])
    expected_sig = hmac.new(SECRET_KEY, payload_bytes, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(parts[1], expected_sig):
        raise ValueError("Invalid token signature")

    payload = json.loads(payload_bytes)

    # Check expiration
    if time.time() > payload["exp"]:
        raise ValueError("Token expired")

    # Check that the presenting agent matches the token subject
    if payload["sub"] != presenting_agent_id:
        raise ValueError(
            f"Token issued to {payload['sub']}, presented by {presenting_agent_id}"
        )

    # Check capability
    if requested_capability not in payload["cap"]:
        raise ValueError(
            f"Capability {requested_capability} not in token scope {payload['cap']}"
        )

    # Check resource (simple prefix matching)
    resource_allowed = False
    for allowed_res in payload["res"]:
        if allowed_res.endswith("*"):
            if requested_resource.startswith(allowed_res[:-1]):
                resource_allowed = True
        elif requested_resource == allowed_res:
            resource_allowed = True
    if not resource_allowed:
        raise ValueError(f"Resource {requested_resource} not in token scope")

    return payload

Delegation Chains with Depth Limits

When a coordinator delegates to Agent B, and Agent B needs to sub-delegate to Agent C, the delegation chain must be tracked and bounded.

# delegation_chain.py
# Tracks and enforces delegation chain depth and scope narrowing.

from dataclasses import dataclass

@dataclass
class DelegationContext:
    chain: list[str]          # [coordinator, agent-b, agent-c]
    original_capabilities: list[str]
    current_capabilities: list[str]
    max_depth: int
    depth: int

    def can_delegate(self) -> bool:
        return self.depth < self.max_depth

    def delegate(
        self,
        from_agent: str,
        to_agent: str,
        narrowed_capabilities: list[str]
    ) -> "DelegationContext":
        """Create a new delegation context with narrowed scope."""
        if not self.can_delegate():
            raise ValueError(
                f"Delegation depth limit reached ({self.max_depth}). "
                f"Chain: {' -> '.join(self.chain)}"
            )

        # Capabilities can only be narrowed, never expanded
        for cap in narrowed_capabilities:
            if cap not in self.current_capabilities:
                raise ValueError(
                    f"Cannot delegate capability '{cap}' - "
                    f"not in current scope: {self.current_capabilities}"
                )

        return DelegationContext(
            chain=self.chain + [to_agent],
            original_capabilities=self.original_capabilities,
            current_capabilities=narrowed_capabilities,
            max_depth=self.max_depth,
            depth=self.depth + 1,
        )
# delegation-policy.yaml
# ConfigMap defining delegation rules for the agent swarm.
apiVersion: v1
kind: ConfigMap
metadata:
  name: agent-delegation-policy
  namespace: ai-agents
data:
  policy.json: |
    {
      "max_delegation_depth": 2,
      "delegation_rules": {
        "agent-coordinator": {
          "can_delegate_to": ["agent-deployer", "agent-analyst", "agent-writer"],
          "max_capability_set": ["read_file", "write_file", "query_database", "kubectl_get", "kubectl_apply"]
        },
        "agent-deployer": {
          "can_delegate_to": ["agent-validator"],
          "max_capability_set": ["kubectl_get", "kubectl_apply"]
        },
        "agent-analyst": {
          "can_delegate_to": [],
          "max_capability_set": ["read_file", "query_database"]
        }
      }
    }

Trust Propagation Limits

Define which agents can communicate directly. Agents outside the trust boundary cannot send messages to each other, even with valid certificates.

# agent-mesh-policy.yaml
# Istio AuthorizationPolicy: restrict which agents can call which.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: agent-communication-policy
  namespace: ai-agents
spec:
  rules:
    # Coordinator can call any agent
    - from:
        - source:
            principals: ["cluster.local/ns/ai-agents/sa/agent-coordinator-sa"]
      to:
        - operation:
            methods: ["POST"]
            paths: ["/v1/delegate"]
    # Deployer can call validator only
    - from:
        - source:
            principals: ["cluster.local/ns/ai-agents/sa/agent-deployer-sa"]
      to:
        - operation:
            methods: ["POST"]
            paths: ["/v1/delegate"]
      when:
        - key: destination.labels[app]
          values: ["agent-validator"]
    # Analyst cannot delegate to anyone (no rule = deny)

Detecting Compromised Agents

Monitor for behavioural anomalies that indicate an agent has been compromised or manipulated.

# Prometheus alerts for compromised agent detection
groups:
  - name: agent-trust-monitoring
    rules:
      - alert: AgentDelegationDepthExceeded
        expr: >
          agent_delegation_depth_current > 2
        labels:
          severity: critical
        annotations:
          summary: "Agent delegation chain exceeded maximum depth"
          runbook: "Possible delegation chain attack. Revoke all tokens. Inspect the full chain."

      - alert: AgentCapabilityEscalation
        expr: >
          increase(agent_capability_escalation_attempts_total[5m]) > 0
        labels:
          severity: critical
        annotations:
          summary: "Agent {{ $labels.agent_id }} attempted capability escalation"
          runbook: "Agent requested capabilities beyond its scope. Likely compromised. Activate kill switch for this agent."

      - alert: AgentUnauthorizedCommunication
        expr: >
          increase(istio_requests_total{
            source_workload=~"agent-.*",
            response_code="403",
            destination_workload=~"agent-.*"
          }[5m]) > 3
        labels:
          severity: warning
        annotations:
          summary: "Agent {{ $labels.source_workload }} making unauthorized calls to {{ $labels.destination_workload }}"

      - alert: AgentTokenReplayDetected
        expr: >
          increase(agent_token_reuse_attempts_total[5m]) > 0
        labels:
          severity: critical
        annotations:
          summary: "Capability token replay detected for agent {{ $labels.agent_id }}"
          runbook: "A capability token was used more times than allowed. Token may have been stolen. Revoke all tokens for this agent."

Audit Logging for Inter-Agent Communication

# agent_comm_audit.py
# Logs every inter-agent message with full delegation context.

import json
import time

def log_agent_message(
    from_agent: str,
    to_agent: str,
    message_type: str,     # "delegate", "response", "capability_request"
    delegation_chain: list[str],
    capabilities_used: list[str],
    token_id: str,
    result: str,           # "accepted", "denied", "error"
):
    entry = {
        "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
        "event": "agent.communication",
        "from_agent": from_agent,
        "to_agent": to_agent,
        "message_type": message_type,
        "delegation_chain": delegation_chain,
        "delegation_depth": len(delegation_chain),
        "capabilities_used": capabilities_used,
        "token_id": token_id,
        "result": result,
    }
    print(json.dumps(entry), flush=True)

Expected Behaviour

  • Every agent has a unique mTLS identity issued by cert-manager, rotated every 24 hours
  • Delegation between agents requires a scoped capability token with a maximum TTL of 5 minutes
  • Capability tokens are non-transferable and single-use by default
  • Delegation depth is limited to 2 hops (coordinator to specialist to validator)
  • Capabilities can only be narrowed during delegation, never expanded
  • Istio AuthorizationPolicy restricts which agents can communicate with each other
  • Capability escalation attempts and token replay trigger critical alerts

Trade-offs

Control Impact Risk Mitigation
mTLS between agents 2-5ms latency per inter-agent call for TLS handshake Latency overhead in chatty multi-agent workflows Use connection pooling. Keep-alive connections between frequently communicating agents.
Single-use capability tokens Each delegation requires a new token issuance Token issuance becomes a bottleneck in high-throughput swarms Batch token issuance for known task patterns. Allow multi-use tokens (max 5) for trusted pairs.
Delegation depth limit of 2 Complex multi-step tasks cannot fan out deeply Tasks requiring 3+ agent hops fail Redesign agent topology to flatten delegation. Or increase depth limit with stricter monitoring.
Non-transferable tokens Agent cannot pass received work to a sub-agent Limits flexibility of agent composition Issue separate tokens from the coordinator for each hop. Coordinator maintains visibility.

Failure Modes

Failure Symptom Detection Recovery
Agent certificate expired Inter-agent calls fail with TLS errors cert-manager certificate status shows expired; agent logs show TLS handshake failure cert-manager auto-renews. If renewal fails: check ClusterIssuer, CA secret, and cert-manager logs.
Capability token key compromised Attacker forges valid delegation tokens Impossible to detect directly. Look for unexpected capability usage patterns. Rotate the HMAC signing key in Vault. All existing tokens become invalid. Re-issue tokens to legitimate agents.
Compromised agent in delegation chain Agent executes unexpected actions under delegated authority Audit logs show actions inconsistent with the task context; behavioural drift alerts fire Revoke all tokens issued to and by the compromised agent. Activate kill switch for that agent. Audit all actions taken during the compromise window.
Delegation policy too restrictive Legitimate multi-agent workflows fail Agents report “delegation denied” errors; tasks stall Review delegation policy against actual workflow requirements. Add specific rules for needed communication paths.

When to Consider a Managed Alternative

Multi-agent trust infrastructure requires cert-manager for identity, a service mesh for communication policy, and a token issuance system for delegation.

  • HCP Vault (#65): Managed PKI for agent certificate issuance and HMAC key storage for capability tokens.
  • Sysdig (#122): Runtime monitoring of agent containers with ML-based anomaly detection for compromised agent behaviour.
  • Grafana Cloud (#108): Centralized dashboards for delegation chains, token usage, and inter-agent communication patterns.

Premium content pack: Multi-agent trust pack. cert-manager Certificate templates, Istio AuthorizationPolicy configs, capability token library, delegation chain tracking, and Prometheus alert rules for multi-agent deployments.