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:
- **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.
- **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.
- **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
- **`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.
- **`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.
- **`root_continuity_probe_receipt`:** Periodic probes confirming the root's continued identity and policy, so hostile changes are detected within bounded latency.
- **`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
- **Does the session trust delegations via a root authority?** If no, standard trust handling applies. If yes, proceed.
- **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.
- **Does the `root_continuity_probe_receipt` confirm the root is unchanged?** If yes, continue trusting. If no, treat as potentially hostile.
- **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
- **Hostile Root Detection:** Root changes surface within the probe interval.
- **Historical Delegation Preservation:** Pre-compromise delegations remain usable.
- **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
)