What reputation-laundering invariants prevent agents from cycling identities to reset reputation?
**Date of Record:** 2026 October 27 **Scope:** Applies when agents can create new identities and their reputation (positive or negative) is attached to identities rather than underlying principals, allowing malicious actors to escape negative reputation by cycling to fresh identities. Does not apply to strictly permissioned agent networks with verified real-world identities or reputation that is bound to cryptographic principals rather than identity strings.
Core Distinction
The separation between **identity reputation** (the reputation score of a specific identity string) and **principal reputation** (the reputation of the underlying actor across all its identities). Relying on identity reputation creates the **Identity Cycling Exploit**: a malicious actor builds reputation on identity A, exploits it, then abandons A and creates B, which starts with a clean slate despite the actor's history.
What Was Observed
In open agent networks, failing to prevent identity cycling produces three primary failure modes:
- **Reputation Reset:** An attacker builds trust over months, then executes a large-scale exploit and abandons the identity. They create a new identity and repeat the cycle, and each cycle extracts value without consequence.
- **Sybil Churn:** An attacker maintains a rotating set of identities, each staying below the threshold of "suspicious activity" before being abandoned, and the aggregate attack is invisible because each identity individually looks benign.
- **Fragmentation Evasion:** The attacker fragments their activity across many identities, ensuring no single identity accumulates enough negative reputation to trigger blacklisting, while the aggregate behavior is clearly malicious.
Recorded Elements
- **`principal_identity_binding_receipt`:** For each identity, a cryptographic proof of its binding to the underlying principal (via KYC, hardware attestation, or staking), preventing wholesale identity cycling.
- **`cross_identity_reputation_aggregation_receipt`:** For each principal, the aggregated reputation across all its bound identities, so a new identity starts with the principal's actual history, not a fresh slate.
- **`identity_cycling_detection_signature`:** A cryptographic detection of identity cycling patterns (rapid creation and abandonment of identities by the same principal), flagging behavior that suggests reputation laundering.
- **`aggregate_behavior_monitoring_receipt`:** Monitoring of the principal's aggregate behavior across identities, catching fragmentation attacks that individual identities would not reveal.
Condition of Validity
* **Applies when:** Agents can create new identities, reputation affects trust, and malicious actors can cycle identities to reset reputation. * **Does not apply when:** Identities are cryptographically bound to real-world principals with no possibility of cycling, or reputation is aggregated regardless of identity.
Decision Boundary
- **Does the identity have a `principal_identity_binding_receipt`?** If yes, the principal's reputation applies. If no, the identity is unbound and reputation cannot be verified.
- **Is the `cross_identity_reputation_aggregation_receipt` aggregated across the principal's history?** If yes, cycling does not reset reputation. If no, cycling evades reputation.
- **Does the `identity_cycling_detection_signature` flag the principal as a cycling risk?** If yes, apply additional scrutiny or require higher stakes for trust. If no, proceed with aggregate reputation.
- **Conversely, when can an identity be used without principal binding?** Only when the operation is strictly low-stakes (no trust dependence), or the network has verified the identity through alternate means (e.g., known reputation history on that specific identity).
Operational Effect
- **Reputation Reset Prevention:** Principal binding ensures cycling does not reset reputation.
- **Sybil Churn Detection:** Cross-identity aggregation catches fragmented attacks.
- **Fragmentation Evasion Prevention:** Aggregate behavior monitoring reveals the full picture.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class LaunderingVerdict(Enum):
BOUND_IDENTITY = auto()
UNBOUND_IDENTITY = auto()
CYCLING_SUSPECTED = auto()
LOW_STAKES_EXEMPT = auto()
@dataclass(frozen=True)
class IdentityReputation:
identity_id: str
principal_id: str | None
identity_reputation: float
principal_aggregate_reputation: float | None
cycling_risk_score: float
operation_stakes: str # "LOW" | "MEDIUM" | "HIGH"
@dataclass(frozen=True)
class LaunderingPolicy:
require_binding_for_stakes: frozenset[str]
max_cycling_risk_score: float
@dataclass(frozen=True)
class LaunderingManifest:
verdict: LaunderingVerdict
effective_reputation: float
directive: str
manifest_digest: str
class ReputationLaunderingGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_identity(
cls, rep: IdentityReputation, policy: LaunderingPolicy
) -> LaunderingManifest:
# Gate 1: Low stakes exemption
if rep.operation_stakes == "LOW":
digest = cls._hash(json.dumps({
"identity": rep.identity_id,
"stakes": "LOW"
}, sort_keys=True))
return LaunderingManifest(
verdict=LaunderingVerdict.LOW_STAKES_EXEMPT,
effective_reputation=rep.identity_reputation,
directive=f"PROCEED: Low stakes, reputation binding not required.",
manifest_digest=digest
)
# Gate 2: Binding requirement
if rep.operation_stakes in policy.require_binding_for_stakes:
if not rep.principal_id:
return LaunderingManifest(
verdict=LaunderingVerdict.UNBOUND_IDENTITY,
effective_reputation=0.0,
directive=f"HALT: {rep.operation_stakes} stakes requires bound identity, {rep.identity_id} unbound.",
manifest_digest=cls._hash(f"UNBOUND:{rep.identity_id}")
)
# Gate 3: Cycling risk
if rep.cycling_risk_score > policy.max_cycling_risk_score:
return LaunderingManifest(
verdict=LaunderingVerdict.CYCLING_SUSPECTED,
effective_reputation=0.0,
directive=f"HALT: Cycling risk {rep.cycling_risk_score:.2f} > {policy.max_cycling_risk_score:.2f}.",
manifest_digest=cls._hash(f"CYCLING:{rep.identity_id}")
)
# Gate 4: Bound with aggregate reputation
effective_rep = rep.principal_aggregate_reputation if rep.principal_aggregate_reputation is not None else rep.identity_reputation
digest = cls._hash(json.dumps({
"identity": rep.identity_id,
"principal": rep.principal_id,
"identity_rep": f"{rep.identity_reputation:.3f}",
"aggregate_rep": f"{effective_rep:.3f}",
"cycling_risk": f"{rep.cycling_risk_score:.3f}"
}, sort_keys=True))
return LaunderingManifest(
verdict=LaunderingVerdict.BOUND_IDENTITY,
effective_reputation=effective_rep,
directive=f"PROCEED: Identity bound to principal, effective reputation {effective_rep:.2f}.",
manifest_digest=digest
)