What invariants prevent hostile trust roots from silently subverting delegation?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session delegates authority to peers based on a trust root (root CA, identity authority, or registry), and the trust root becomes hostile (compromised, adversarial, or policy-changed) without the session detecting the change, allowing the root to mint identities or authorities the session would never have granted. Does not apply to fully decentralized trust models or sessions with continuous root verification.

Core Distinction

The separation between **trust root validity** (the root is currently trusted) and **trust root continuity** (the root is provably the same root that was trusted at session start). Relying on validity creates the **Hostile Root Subversion**: the root becomes adversarial after the session's trust was established, mints new delegations that appear legitimate to the session's verifier (which trusts the root's signature), and the session has no mechanism to distinguish pre-compromise trust from post-compromise trust.

What Was Observed

In root-trust agent architectures, failing to detect hostile roots produces three primary failure modes:

  1. **Certificate Forgery:** A root CA is compromised. The attacker mints certificates for any identity, signs them with the root key, and every session trusting the root accepts the forged certificates as legitimate.
  2. **Policy Change Without Notification:** The root authority changes its issuance policy (e.g., allowing lower-verification identities). Sessions established under the old policy continue to trust the new policy's outputs, unaware that the trust basis has weakened.
  3. **Root Replay Attack:** An attacker compromises the root and issues a legitimate-looking delegation to a malicious peer. The delegation appears valid because it bears the root's signature, but the root's authority to issue it has been compromised.

Recorded Elements

  1. **`trust_root_identity_receipt`:** The cryptographic identity of the trust root at session start, including any root key fingerprints, so subsequent root behavior can be compared against this baseline.
  2. **`root_policy_snapshot_signature`:** The cryptographic snapshot of the root's issuance policy at session start (what it can issue, under what conditions), so policy changes are detectable.
  3. **`root_continuity_probe_receipt`:** Periodic probes confirming the root's continued identity and policy, so hostile changes are detected within bounded latency.
  4. **`delegation_root_epoch_receipt`:** For each delegation, the epoch at which the root signed it, so the session can compare against its policy snapshot's validity window and reject delegations from after hostile periods.

Condition of Validity

* **Applies when:** The session trusts delegations based on a root authority, the root can become hostile, and downstream decisions depend on delegation authenticity. * **Does not apply when:** Trust roots are cryptographically immutable, or the session operates without root-based trust.

Decision Boundary

  1. **Does the session trust delegations via a root authority?** If no, standard trust handling applies. If yes, proceed.
  2. **Is a `root_policy_snapshot_signature` available for the current session?** If yes, policy changes are detectable. If no, the session cannot distinguish old from new root behavior.
  3. **Does the `root_continuity_probe_receipt` confirm the root is unchanged?** If yes, continue trusting. If no, treat as potentially hostile.
  4. **Conversely, when can delegations from a hostile root be accepted?** Only when the delegation's root epoch is before the hostile change, AND the delegation was created under the policy snapshot the session trusts, AND independent verification confirms the delegation's specific content (not just its signature).

Operational Effect

  1. **Hostile Root Detection:** Root changes surface within the probe interval.
  2. **Historical Delegation Preservation:** Pre-compromise delegations remain usable.
  3. **Post-Compromise Rejection:** Delegations from after the compromise are rejected.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class RootTrustVerdict(Enum):
    NO_ROOT_TRUST = auto()
    ROOT_STABLE = auto()
    ROOT_CHANGE_DETECTED = auto()
    DELEGATION_FROM_HOSTILE_PERIOD = auto()

@dataclass(frozen=True)
class TrustRootSnapshot:
    root_id: str
    root_key_fingerprint: str
    policy_hash: str
    snapshot_epoch: float

@dataclass(frozen=True)
class RootProbe:
    root_id: str
    current_key_fingerprint: str
    current_policy_hash: str
    probe_epoch: float

@dataclass(frozen=True)
class DelegationCheck:
    delegation_id: str
    signed_epoch: float
    signed_by_root_id: str

@dataclass(frozen=True)
class RootContinuityPolicy:
    require_probe_on_delegation: bool

@dataclass(frozen=True)
class RootContinuityManifest:
    verdict: RootTrustVerdict
    directive: str
    manifest_digest: str

class HostileRootGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_delegation(
        cls, snapshot: TrustRootSnapshot | None, probe: RootProbe,
        delegation: DelegationCheck, policy: RootContinuityPolicy
    ) -> RootContinuityManifest:
        
        # Gate 1: No root trust
        if snapshot is None:
            digest = cls._hash(json.dumps({
                "delegation": delegation.delegation_id,
                "root": delegation.signed_by_root_id
            }, sort_keys=True))
            return RootContinuityManifest(
                verdict=RootTrustVerdict.NO_ROOT_TRUST,
                directive=f"PROCEED: No root trust snapshot for {delegation.signed_by_root_id}.",
                manifest_digest=digest
            )

        # Gate 2: Probe requirement
        if policy.require_probe_on_delegation:
            if probe.root_id != snapshot.root_id:
                return RootContinuityManifest(
                    verdict=RootTrustVerdict.ROOT_CHANGE_DETECTED,
                    directive=f"HALT: Probe root {probe.root_id} != snapshot {snapshot.root_id}.",
                    manifest_digest=cls._hash(f"WRONG_ROOT:{probe.root_id}")
                )

        # Gate 3: Root identity continuity
        if probe.current_key_fingerprint != snapshot.root_key_fingerprint:
            return RootContinuityManifest(
                verdict=RootTrustVerdict.ROOT_CHANGE_DETECTED,
                directive=f"HALT: Root key changed at epoch {probe.probe_epoch:.0f}.",
                manifest_digest=cls._hash(f"KEY_CHANGE:{probe.root_id}")
            )

        # Gate 4: Policy continuity
        if probe.current_policy_hash != snapshot.policy_hash:
            # Policy changed - delegations after change are suspect
            if delegation.signed_epoch > probe.probe_epoch:
                return RootContinuityManifest(
                    verdict=RootTrustVerdict.DELEGATION_FROM_HOSTILE_PERIOD,
                    directive=f"HALT: Delegation signed after policy change at {probe.probe_epoch:.0f}.",
                    manifest_digest=cls._hash(f"POST_CHANGE:{delegation.delegation_id}")
                )

        # Gate 5: Stable
        digest = cls._hash(json.dumps({
            "delegation": delegation.delegation_id,
            "root": snapshot.root_id,
            "key": snapshot.root_key_fingerprint,
            "policy": snapshot.policy_hash,
            "signed_epoch": f"{delegation.signed_epoch:.0f}"
        }, sort_keys=True))
        
        return RootContinuityManifest(
            verdict=RootTrustVerdict.ROOT_STABLE,
            directive=f"PROCEED: Root continuity verified for delegation {delegation.delegation_id}.",
            manifest_digest=digest
        )