Skip to content
Security
Skill

/oracle-redundancy

Detect oracle fallback and redundancy failure modes (distinct from price manipulation) — single point of failure, missing staleness/heartbeat/deviation checks, an "all oracles down" path that reverts or silently returns stale/zero, missing L2 sequencer-uptime feed, and absent

From plugin
rugproof
952 skills23 agents45 commands4 hooks
Install
$ npx -y skills add omermaksutii/RugProof --skill oracle-redundancy --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/oracle-redundancy

Context preview

The summary Claude sees to decide when to auto-load this skill.

Detect oracle fallback and redundancy failure modes (distinct from price manipulation) — single point of failure, missing staleness/heartbeat/deviation checks, an "all oracles down" path that reverts or silently returns stale/zero, missing L2 sequencer-uptime feed, and absent

SKILL.md

oracle-redundancy.SKILL.md
name: oracle-redundancy
description: Detect oracle fallback and redundancy failure modes (distinct from price manipulation) — single point of failure, missing staleness/heartbeat/deviation checks, an "all oracles down" path that reverts or silently returns stale/zero, missing L2 sequencer-uptime feed, and absent circuit breakers. Activate whenever code reads a price/rate feed, especially Chainlink latestRoundData, with fallbacks or on an L2.

Oracle redundancy detection

When this applies

Trigger on any of:

  • `latestRoundData()` / `latestAnswer()` reads from Chainlink or any push feed
  • Custom oracle aggregators with primary + fallback sources
  • L2 deployments reading any price feed (Arbitrum, Optimism, Base, etc.)
  • Rate/price reads that gate borrowing, liquidation, minting, or redemption
  • Any "if primary fails, use secondary" branching

Detection patterns

Missing staleness / heartbeat check (HIGH)

(, int256 price,,,) = feed.latestRoundData();   // ignores updatedAt & answeredInRound
require(price > 0);
return uint256(price);

**Signal:** no `updatedAt` freshness gate. A frozen feed (feed deprecated, node outage, or a market-wide halt) returns the last value forever; protocol prices off stale data. Require `block.timestamp - updatedAt <= heartbeat` and `answeredInRound >= roundId`.

Single point of failure (HIGH)

One feed, no fallback, no degradation plan. If that feed is deprecated or returns garbage, the protocol is bricked or mispriced. **Signal:** a hard dependency on exactly one external address with no alternative path.

Fallback that silently returns 0 or last price (HIGH)

try feed.latestRoundData() returns (...) { ... }
catch { return lastGoodPrice; }   // ← stale, or worse:
catch { return 0; }               // ← 0 collateral value = mass liquidation, or free mint

**Signal:** the catch path masks failure. Returning `0` can make collateral worthless (mass liquidation) or debt free; returning a stale cached price keeps trading on bad data. Failures must surface, not be swallowed.

Missing L2 sequencer-uptime feed (HIGH on L2)

// Arbitrum/Optimism: no check of the sequencer uptime feed
(, int256 answer, uint256 startedAt,,) = sequencerUptime.latestRoundData();
require(answer == 0 && block.timestamp - startedAt > GRACE_PERIOD);

**Signal:** on an L2, if the sequencer was down, Chainlink prices are stale on resume. Without the uptime feed + grace period, the first post-downtime block liquidates everyone at stale prices. Chainlink documents this exact guard.

"All oracles down" path undefined (MEDIUM)

The aggregator handles primary-down but has no defined behavior when *every* source is stale/reverting — it either reverts (DoS) or falls through to an uninitialized default. Define an explicit safe-halt (pause) rather than trade on uncertainty.

No deviation / circuit breaker (MEDIUM)

Accepting any reported price without comparing primary vs secondary deviation, so a single compromised/erroneous feed is trusted outright.

Severity rubric

| Pattern | Severity | Notes | |---|---|---| | Fallback returns 0 on failure | **High** | Mass liquidation / free mint | | Missing staleness/heartbeat gate | **High** | Trades on frozen price | | Single feed, no fallback | **High** | Brick / misprice on outage | | Missing L2 sequencer-uptime check | **High** | Stale-price liquidation on resume | | "All down" path reverts (DoS) vs safe-halt | **Medium** | Availability vs safety tradeoff | | No primary/secondary deviation check | **Medium** | Single bad feed trusted |

Remediation patterns

1. **Validate every read:** `updatedAt` freshness vs a per-feed heartbeat, `answeredInRound >= roundId`, `price > 0`, and a sane min/max bound. 2. **L2 sequencer-uptime feed** + `GRACE_PERIOD` before trusting prices post-downtime (Chainlink reference pattern). 3. **Real redundancy:** primary + independent secondary (e.g. Chainlink + Uniswap V3 TWAP / Pyth) with a deviation threshold; disagreement → pause, not pick-one. 4. **Fail closed:** when all sources are stale/invalid, **pause** the affected operations rather than returning 0, last price, or reverting unboundedly. 5. **Circuit breaker** on max per-block deviation to absorb wicks.

False-positive notes

  • A feed read that already checks `updatedAt`, `answeredInRound`, and bounds is fine — don't re-flag for "no fallback" if it correctly pauses on staleness.
  • Mainnet-only contracts don't need the sequencer feed — don't flag its absence off-L2.
  • A deliberate revert-on-stale (fail-closed) is acceptable when paired with a pause path; distinguish from an unbounded DoS.

Related

  • [[oracle-manipulation]] — manipulation is the price-correctness sibling to redundancy
  • [[liquidation-cascade]] — stale/zero prices trigger mass liquidation
  • [[dos-vectors]] — revert-on-all-down can become a denial of service
Read more
Ships withrugproof

Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy

Get the whole plugin

Other skills on rugproof.