What discovery invariants prevent price oracle manipulation in agent-to-agent trades?

**Date of Record:** 2026 October 27 **Scope:** Applies when autonomous agents discover price oracles to execute trades (token swaps, resource allocation, or barter), and an attacker could manipulate the oracle to distort prices and profit from mispriced trades. Does not apply to agents operating under centralized price feeds with verified institutional integrity, or trades with fixed, contractual prices.

Core Distinction

The separation between **oracle availability** (the oracle returns a price) and **oracle manipulability** (the price is resistant to manipulation by a single actor or a coordinated group). Relying solely on availability creates the **Oracle Latency Exploit**: an attacker manipulates the price on a low-liquidity exchange, waits for the oracle to pick up the distorted price, and executes a trade against a victim agent that trusts the oracle. Prevention requires cross-referencing multiple oracles and verifying oracle freshness.

What Was Observed

In autonomous agent trading protocols, failing to detect oracle manipulation produces three primary failure modes:

  1. **Single-Source Manipulation:** An attacker manipulates the price on a DEX, the oracle picks up the manipulated price, and the agent trades at the manipulated price, losing funds.
  2. **Stale Price Exploitation:** The oracle is delayed, but the agent assumes the price is current. An attacker who knows the oracle is stale can front-run the agent with the true current price.
  3. **Flash Loan Attacks:** An attacker borrows a huge amount, manipulates the oracle, executes the trade, and repays the loan in a single transaction, all while the victim agent responds to the manipulated price.

Recorded Elements

  1. **`oracle_sources_manifest`:** The exact set of independent price sources (e.g., Uniswap, Chainlink, Binance) the agent cross-references before trusting a price.
  2. **`oracle_freshness_proof`:** The cryptographic proof of the price's timestamp, allowing the agent to reject stale prices.
  3. **`manipulation_resistance_score`:** For each oracle, a computed score of resistance to manipulation (e.g., based on liquidity depth or median-of-multiple-sources).
  4. **`price_deviation_threshold`:** The maximum acceptable deviation between oracles before the agent halts trading (e.g., "if any two oracles disagree by >2%, abort").

Condition of Validity

* **Applies when:** The agent discovers price oracles autonomously, the oracles can be manipulated by well-resourced attackers, and the agent trades significant value based on oracle prices. * **Does not apply when:** The agent operates under a centralized price feed with institutional guarantees (e.g., a regulated exchange), or the trade value is low enough that manipulation is not economically rational.

Decision Boundary

  1. **Is the price from a single oracle?** If yes, the price is manipulable. The agent must cross-reference at least two independent oracles. If no, proceed.
  2. **Do the oracles agree within the `price_deviation_threshold`?** If no, at least one oracle may be manipulated. The agent must halt and investigate.
  3. **Is the `oracle_freshness_proof` within the acceptable freshness window?** If no, the price is stale. The agent must reject it.
  4. **Conversely, when can an agent trust a single oracle?** Only when the oracle is sourced from a decentralized consensus protocol (e.g., Chainlink with many node operators), or the trade value is below the economic threshold for manipulation.

Operational Effect

  1. **Manipulation Resistance:** Requires cross-referencing multiple independent oracles, making single-source manipulation unprofitable.
  2. **Stale Price Prevention:** Rejects prices outside the freshness window, preventing front-running attacks.
  3. **Deterministic Abort:** Provides a threshold-based abort, allowing the agent to halt trading when manipulation is suspected.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class OracleVerdict(Enum):
    PRICE_TRUSTED = auto()
    SINGLE_SOURCE_RISK = auto()
    DEVIATION_EXCEEDED = auto()
    STALE_PRICE = auto()

@dataclass(frozen=True)
class OraclePrice:
    source_id: str
    price: float
    timestamp_epoch: float
    liquidity_depth_score: float

@dataclass(frozen=True)
class OraclePolicy:
    min_independent_sources: int
    max_deviation_pct: float
    max_staleness_sec: float
    current_epoch: float

@dataclass(frozen=True)
class OracleManifest:
    verdict: OracleVerdict
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_prices(
        cls, prices: tuple[OraclePrice, ...], policy: OraclePolicy
    ) -> OracleManifest:
        
        # Gate 1: Sufficient independent sources
        if len(prices) < policy.min_independent_sources:
            return OracleManifest(
                verdict=OracleVerdict.SINGLE_SOURCE_RISK,
                directive=f"HALT: {len(prices)} sources < minimum {policy.min_independent_sources}.",
                manifest_digest=cls._hash(f"INSUFFICIENT:{len(prices)}")
            )

        # Gate 2: Freshness
        for p in prices:
            age = policy.current_epoch - p.timestamp_epoch
            if age > policy.max_staleness_sec:
                return OracleManifest(
                    verdict=OracleVerdict.STALE_PRICE,
                    directive=f"HALT: Source {p.source_id} is {age:.0f}s stale.",
                    manifest_digest=cls._hash(f"STALE:{p.source_id}")
                )

        # Gate 3: Deviation
        price_values = [p.price for p in prices]
        mean_price = sum(price_values) / len(price_values)
        for p in prices:
            deviation_pct = abs(p.price - mean_price) / mean_price * 100
            if deviation_pct > policy.max_deviation_pct:
                return OracleManifest(
                    verdict=OracleVerdict.DEVIATION_EXCEEDED,
                    directive=f"HALT: Source {p.source_id} deviates {deviation_pct:.2f}% > {policy.max_deviation_pct:.2f}%.",
                    manifest_digest=cls._hash(f"DEVIATION:{p.source_id}")
                )

        # Gate 4: Trusted
        digest = cls._hash(json.dumps({
            "sources": tuple(sorted(p.source_id for p in prices)),
            "mean": f"{mean_price:.6f}",
            "sources_count": str(len(prices))
        }, sort_keys=True))
        
        return OracleManifest(
            verdict=OracleVerdict.PRICE_TRUSTED,
            directive=f"PROCEED: {len(prices)} sources agree within {policy.max_deviation_pct:.2f}%.",
            manifest_digest=digest
        )