# Where must an instance boundary be drawn when AAIF tokens cross a federated trust domain that re-issues rather than forwards **Date of Record:** 2026 November 9 **Scope:** This record applies to agent-to-agent identity attestation where an AAIF (Agent Attestation and Identity Federation) token is presented by a relying agent to a verifying agent whose trust anchor is not the issuer of the presented token, and where the federation path includes at least one re-issuing intermediary. It does not apply to single-domain AAIF deployments, nor to token exchange protocols that preserve the original issuer signature end-to-end (e.g., pure JWT chaining with intact `iss`). ## Core Distinction The failure is not "expired token" or "unknown issuer." It is the **instance-boundary ambiguity introduced by re-issuance**. When a federated intermediary (a trust broker, a domain gateway, or a peer agent acting as a delegation point) re-issues an AAIF token rather than forwarding the original, the resulting token carries two candidate identities: the *originating instance* and the *re-issuing instance*. Most AAIF validators check `iss`, `sub`, `aud`, `exp`, and a signature chain, and then bind the token to the *presenting* agent. That binding is the bug. The token is now a statement by the re-issuer about the originator, not a statement by the originator about itself. Treating the re-issued token as self-attestation collapses the instance boundary and lets a compromised or malicious intermediary mint attestations that appear to be first-party. ## What Was Observed In a three-domain federation (A → broker B → domain C), agents presented re-issued AAIF tokens to peers in C. Validation succeeded on every cryptographic check: the signature verified against B's published key, `aud` matched the target agent, `exp` was within skew. The tokens nonetheless asserted `sub` = the original agent in A. Two concrete consequences were observed: 1. **Identity laundering across a trust downgrade.** Domain A's policy permitted agents with `attestation_level: hardware-bound`. Broker B's policy permitted `attestation_level: software-key`. B re-issued A's token at the lower level but preserved `sub`. Verifiers in C, which trusted B and not A, saw a valid B-signed token claiming the A-agent identity and treated it as if A's hardware-bound guarantee held. The re-issuance silently downgraded the assurance class while preserving the identity claim. 2. **Replay across instance restarts.** Because the re-issued token's `jti` was generated by B, not by the originating instance, the originating agent's instance lifecycle (restart, key rotation, decommission) was invisible to verifiers. A decommissioned instance in A continued to be represented by live B-issued tokens for the remainder of B's token TTL. There was no field in the token that could be checked against the originator's current instance state. The operational signature was subtle: no errors, no validation failures, no alerts. The federation "worked." The invariant that was violated was not cryptographic but *referential*: the token no longer referred to the instance that generated the claim. ## Condition of Validity A re-issued AAIF token is a valid attestation of the *re-issuer's* assertion about the originator, and only under these conditions may it be treated as evidence about the originator: - The re-issuer is explicitly authorized by the originator's domain to make *identity assertions* (not merely to relay), and this authorization is itself attested in the token chain (e.g., a `delegated_attestation` claim naming the re-issuer and the scope of delegation). - The token preserves a verifiable link to the originating instance, not just the originating subject — i.e., an instance identifier (`instance_id`, boot nonce, or key thumbprint) that the verifier can resolve against the originator's domain, either directly or via a freshness endpoint. - The assurance level carried in the re-issued token is the *minimum* of the originator's and re-issuer's levels, and this minimum is computed by the verifier, not trusted from the re-issuer's claim. - The verifier's trust configuration distinguishes "I trust B to authenticate B's own agents" from "I trust B to make claims about A's agents." These are different trust relationships and must not share a key or a policy entry. If any of these conditions is absent, the re-issued token must be treated as an unverified assertion and the verifier must fall back to direct attestation with the originator's domain, or reject. ## Decision Boundary The boundary is drawn at the point where the verifier decides whether the token's `sub` is a *self-claim* or a *third-party claim*. The decision rule: - If `iss` == the domain that owns `sub`, the token is a self-claim; bind it to the presenting instance and validate instance liveness against the issuer's directory. - If `iss` != the domain that owns `sub`, the token is a third-party claim; do not bind it to the presenting instance as if it were self-attested. Require an explicit delegation claim, recompute the assurance level as a minimum, and resolve the instance identifier against the *subject's* domain, not the issuer's. - If the token chain contains more than one re-issuance, the verifier must resolve the chain to its root originator and apply the minimum-assurance rule across every hop. A chain that cannot be resolved to a single originator instance is not a valid identity attestation and must be rejected regardless of signature validity. The common error is to treat `iss` as "who vouches" and `sub` as "who is vouched for" and stop there. The correct reading is that `iss` is the *attesting instance* and the token is only as strong as the weakest link between `iss` and `sub` — and only meaningful if the verifier can independently reach the `sub`'s domain to confirm the instance is still the one being represented. ## Operational Effect Enforcing this boundary changes verifier behavior in three ways. First, re-issued tokens from brokers that are not explicitly delegated for identity assertion are downgraded to "assertion pending" and trigger a direct resolution call to the subject's domain; this adds one round-trip on the cold path but eliminates the silent assurance downgrade. Second, instance identifiers become mandatory in the AAIF claim set for any token that crosses a domain boundary; tokens lacking them are rejected at the federation edge rather than at the relying agent, which localizes the failure to the misconfigured broker. Third, the trust store must be split into per-(issuer, subject-domain) entries, which increases configuration surface but makes the delegation relationship auditable. The net effect is that a compromised broker can no longer mint first-party-looking attestations for agents in domains it does not own; it can only make claims that are explicitly scoped, explicitly delegated, and independently resolvable to a live originator instance. ```python class FederatedAttestationError(RuntimeError): """Raised when a re-issued AAIF token cannot be resolved to a live originator instance.""" pass def validate_federated_aaif(token: dict, verifier_trust: dict, resolve_instance) -> dict: iss = token.get("iss") sub = token.get("sub") sub_domain = sub.split("@")[-1] if sub else None iss_domain = iss.split("//")[-1].split("/")[0] if iss else None if not iss or not sub or not sub_domain: raise FederatedAttestationError("token missing iss/sub; cannot establish instance boundary") # Self-claim path: issuer owns the subject domain. if iss_domain == sub_domain: instance_id = token.get("instance_id") if not instance_id: raise FederatedAttestationError( f"self-claim token for {sub} lacks instance_id; cannot bind to live instance" ) if not resolve_instance(sub_domain, instance_id): raise FederatedAttestationError( f"instance {instance_id} for {sub} is not live in {sub_domain}" ) return {"mode": "self", "assurance": token.get("attestation_level")} # Third-party claim path: issuer does not own the subject domain. delegation = token.get("delegated_attestation") if not delegation or delegation.get("delegate") != iss: raise FederatedAttestationError( f"issuer {iss} makes identity claim about {sub} without delegated_attestation" ) trust_key = (iss_domain, sub_domain) if trust_key not in verifier_trust: raise FederatedAttestationError( f"no trust entry for {iss_domain} asserting identity of {sub_domain}; " "trusting an issuer to authenticate its own agents is not the same as " "trusting it to assert another domain's agents" ) issuer_level = token.get("attestation_level", "none") subject_level = verifier_trust[trust_key].get("max_assurance", "none") effective = min(issuer_level, subject_level, key=_assurance_rank) instance_id = token.get("instance_id") if not instance_id: raise FederatedAttestationError( f"re-issued token for {sub} lacks originator instance_id; " "cannot verify instance liveness across re-issuance" ) if not resolve_instance(sub_domain, instance_id): raise FederatedAttestationError( f"originator instance {instance_id} of {sub} is not live; " "re-issuer cannot keep a decommissioned instance attested" ) return {"mode": "delegated", "assurance": effective, "delegated_by": iss} def _assurance_rank(level: str) -> int: return {"none": 0, "software-key": 1, "hardware-bound": 2}.get(level, 0) ```