Rho Markets Scroll ETH Oracle / WBTC Feed Misconfiguration MEV Bad Debt (2024-07-19)

  • Name: Rho Markets Scroll ETH oracle / WBTC feed misconfiguration MEV bad debt
  • Date: 2024-07-19
  • Protocol: Rho Markets
  • Chain: Scroll
  • Category: oracle configuration failure / wrong-asset feed binding / market-launch misconfiguration
  • Loss: about $7.5M-$7.6M temporarily borrowed into bad debt; funds were later returned
  • Summary: Shortly after updating contracts for a new market launch on Scroll, Rho Markets misconfigured its oracle registry so that ETH collateral in the rETH market was priced from the WBTC / USD feed. Compound-style semantics in Rho’s PriceOracleV2 treat address(0) as ETH, so the bad binding did not break contract execution — it simply made about 1 ETH look like roughly 1 BTC. An MEV bot noticed the opportunity, minted rETH, borrowed stronger assets including wstETH, USDC, USDT, STONE, and wrsETH up to their borrow caps, and left about $7.5M of bad debt before later returning the funds after coordination with Rho, SEAL 911, and Scroll.
  • Trigger / entry point:
    • The incident happened during deployment work for a new market launch on Scroll.
    • Rho’s official incident report says the ETH oracle price feed was erroneously configured to the BTC price feed because a deployment-process validation step was missed.
    • Dedaub’s reconstruction says the onchain oracle update at block 7580111 set the feed for underlying asset address(0) to the WBTC / USD oracle.
    • In Compound-derived oracle semantics, address(0) is the underlying for native ETH markets, so this bad mapping affected rETH, not the newly intended rWBTC market.
    • Dedaub also notes that rWBTC had been deployed on block 7579842 but no setRTokenConfig call for that market had yet been made before the faulty oracle update.
  • Root cause:
    • This was a deployment-side oracle configuration failure, not a smart-contract logic bug in the lending core.
    • The decisive mistake was a wrong-asset feed binding: the oracle interface remained valid and returned a real market price, but for the wrong asset.
    • Because ETH was silently mapped to WBTC / USD, the protocol overvalued ETH collateral by roughly 20x.
    • The deeper preserved lesson is that launch scripts, feed registries, and address conventions like Compound’s address(0) == ETH are themselves part of the solvency boundary.
  • Exploit path:
    1. Rho deployed and updated contracts for a new Scroll market launch.
    2. During oracle initialization, the ETH slot in PriceOracleV2 was bound to the WBTC / USD feed instead of the correct ETH feed.
    3. The protocol therefore treated ETH collateral supplied to rETH as if it were worth about one bitcoin per ether rather than one ether.
    4. An MEV bot detected the opportunity and front-ran the opening with exploit tx 0x0a7b4c6542eb8f37de788c8848324c0ae002919148a4426903b0fb4149f88f05.
    5. In a representative transaction described by Dedaub, the bot minted about 84 rETH, borrowed about 942 wstETH, and swapped the proceeds back into ETH; across the incident, official reporting says it also borrowed USDC, USDT, STONE, and wrsETH up to borrow caps.
    6. The result was about $7.5M-$7.6M of protocol bad debt created in minutes by ordinary borrow logic honoring a false collateral value.
    7. The bot then sent an onchain message in tx 0xab7bc87fca7df222000b870fbe55750c33b3ea0461a8ba8a8ddbe530a1934248, offered to return the funds if Rho acknowledged the issue was its own misconfiguration, and ultimately returned funds in tx 0x15da6af0207d82d27ca20a542dae1b81580ca1cbfee7028c312229968e356446.
  • What the attacker needed to be true:
    • The final oracle output had to be accepted as borrow power without any sanity bound comparing ETH’s quoted price to a plausible ETH/USD range.
    • There needed to be meaningful borrowable liquidity in stronger assets once ETH collateral was mispriced.
    • Deployment validation had to fail in a way that preserved ABI correctness and normal control flow, so the protocol would not revert or obviously brick before exploitation.
    • The opportunity had to remain live long enough for a searcher or MEV bot to notice and execute before operators paused markets.
  • Technical anatomy worth remembering:
    • This is a clean wrong asset, correct interface oracle failure. The feed itself was live and the contract path was functioning; the protocol simply asked the wrong oracle what ETH was worth.
    • It is therefore a strong contrast case for oracle-manipulation: nobody had to move ETH or BTC markets, spoof a report, or corrupt Chainlink. Rho published the false solvency number on its own.
    • The Compound convention that native ETH is represented by address(0) made this bug class sharper. A deployment operator could think they were assigning a new market feed while actually rewriting the existing ETH-underlying slot.
    • The exploit also shows why launch sequencing is part of oracle safety. Dedaub’s reconstruction preserves that rWBTC had been deployed but not yet fully configured, so an in-between deployment state was already live enough to be exploited.
    • It is also a clean production-ops boundary failure: the same authorized deployment step that was supposed to prepare a new market still had power to rewrite live ETH collateral truth for the existing market set, with no bounded preview or canary phase between candidate launch config and money-good borrow power.
    • The incident is also a reminder that MEV searchers arbitrage configuration mistakes just as ruthlessly as they arbitrage price mistakes. Once the wrong feed was onchain, the monetization step was just a normal borrow.
  • Representative transactions and artifacts:
    • MEV bot exploit tx: 0x0a7b4c6542eb8f37de788c8848324c0ae002919148a4426903b0fb4149f88f05
    • Onchain negotiation message tx: 0xab7bc87fca7df222000b870fbe55750c33b3ea0461a8ba8a8ddbe530a1934248
    • Funds-return tx: 0x15da6af0207d82d27ca20a542dae1b81580ca1cbfee7028c312229968e356446
    • rETH configuration tx cited by Dedaub: 0x64c57738b5d9c3993c5df596f0809d04c2e4ff55bb4d86227a52fc3fa82bab91
    • rWBTC deployment tx cited by Dedaub: 0x777b62a27ff9799795f3f8026e467434d2186ae549babdabc4e251f3499ea5ab
  • Response / mitigation:
    • Rho paused vulnerable protocol components immediately after detection.
    • SEAL 911, Scroll, Dedaub, Hexagate, SlowMist, BlockSec, ZachXBT, and others joined the response effort cited by the protocol.
    • Scroll temporarily halted the chain during the response window.
    • The MEV bot returned the funds, so Rho later stated that no user funds were ultimately lost.
    • Rho’s published remediation plan emphasized tighter deployment review, Tenderly-fork testing for upgrades and oracle changes, cleaner deployment environments, and additional third-party verification before mainnet updates.

Pattern tags

  • oracle-configuration-failure
  • price-domain-and-reciprocal-range-discipline
  • collateral-admission-lag-and-borrow-side-quarantine
  • The preserved failure was not BTC price moved or Chainlink failed; it was Rho published the wrong asset identity into the final collateral-price slot.
  • This is a clean wrong asset, correct interface case. The WBTC / USD feed was live and economically meaningful, but it was semantically wrong for ETH collateral once address(0) still meant native ETH inside the Compound-style oracle map.
  • The incident is also a launch-state publication failure: an in-progress rWBTC rollout step still retained power to rewrite money-good ETH borrow truth for an already-live market.

Why the exploit worked

  • Rho’s deployment process validated too weakly for the real balance-sheet risk. The official report says the ETH oracle feed was supposed to be checked before changes were applied, but one missed validation step meant an otherwise normal config write could silently swap ETH / USD semantics for WBTC / USD semantics without breaking contract execution.
  • The final solvency object had no strong identity or plausibility guard. Dedaub’s reconstruction preserves that the oracle update wrote the WBTC / USD feed into the address(0) slot, and Compound-style conventions meant address(0) already stood for native ETH. The protocol therefore accepted a real market answer for the wrong asset as if it were normal ETH collateral truth.
  • Rho also let a freshly changed oracle path become immediate borrow authority. There was no observation-only window, canary, or borrow-side quarantine between deployment script writes new feed mapping and permissionless borrowers may lever against the new output.
  • That made the monetization path brutally simple. The MEV bot did not need to manipulate BTC, move ETH, or break Chainlink; once Rho published ~1 BTC per 1 ETH as borrowable collateral truth, ordinary mint-and-borrow logic was enough to extract wstETH, USDC, USDT, STONE, and wrsETH up to caps.
  • The incident therefore preserves a sharper design lesson than check your deployment scripts: feed identity, address conventions, and launch sequencing were one joined solvency object, and Rho treated them as separable operational details until the market started honoring the wrong one.

Detection and audit pivots

  • For every oracle-registry write, verify the final solvency object in plain language: this market will publish ETH / USD, not merely this feed address is valid.
  • Treat special address conventions like Compound’s address(0) == ETH as security-critical state, not developer shorthand. Any deployment or governance tool that writes by raw underlying address should prove which already-live market that slot controls.
  • Diff old and new collateral prices against independent references before activation. If an ETH market suddenly moves toward the BTC range, the update should fail closed rather than publish.
  • Separate launch scripting from live borrow authority. A new-market rollout should not be able to rewrite an existing market’s collateral truth without a narrower review step, a preview environment, or a staged activation window.
  • Keep asset-local freezes or borrow-side quarantine close to oracle changes. If a fresh mapping still looks plausible to the contract interface, the protocol needs a faster local brake than human recognition plus coordinated response.

Failure-prevention checklist

  • Treat asset-to-feed binding as typed solvency state, not as a generic address map. Deployment tooling should require operators to prove both market identity and quote object before a write can touch a live collateral slot.
  • Split new-market rollout authority from already-live market authority. If a deployment is meant to add rWBTC, the same step should not still be able to rewrite the ETH slot without a narrower, separately reviewed action.
  • Add publication-boundary plausibility checks for blue-chip collateral. If ETH suddenly moves into the BTC price range, fail closed, page operators, and hold borrowing disabled until the discrepancy is explicitly cleared.
  • Keep oracle changes in canary or shadow mode before they become full borrow authority. A new or rewritten price path should survive reference diffs, range checks, and operator review before permissionless users can lever against it.
  • Make special address conventions explicit in tooling. If address(0) means native ETH, the deployment surface should render that fact loudly enough that an operator cannot mistake it for a fresh market placeholder.
  • Rehearse launch and upgrade scripts on forks using the final live state, not only local deployment assumptions. The useful test is what already-live market did this write actually change?, not merely did the transaction succeed?.
  • Keep scoped emergency brakes close to market activation. Borrow caps, collateral factors, or market-specific pauses should be easy to cut immediately when a fresh configuration diverges from expected truth.

Audit prompts

  • Which exact market slot does each oracle-registry write affect after inherited conventions like address(0) == ETH are applied?
  • Can a deployment meant for a new market still overwrite price truth for an already-live market, and what narrower approval boundary prevents that?
  • Where does the rollout prove semantic identity such as this is ETH / USD rather than only structural validity such as this feed address is live and ABI-compatible?
  • What independent reference, domain check, or reciprocal/range check would block ETH from being published near the BTC price range?
  • Does the protocol distinguish new feed mapping written successfully from market may now use that mapping as borrow power, or are those still the same state transition?
  • What fork-test or simulation diff shows pre-change versus post-change prices for every affected live market before mainnet activation?
  • If a market-launch step fails semantically but not syntactically, what local control can freeze just the affected market before generalized bad debt forms?

Lessons that should already be standard

  • Correct interface is not the same as correct asset. A live oracle answer for the wrong market is still false collateral truth.
  • Launch scripts and registry writes are balance-sheet code. If they can alter what a mature market treats as money-good collateral value, they deserve the same invariant review as contract logic.
  • Special address semantics are attack surfaces when hidden inside operator tooling. address(0) is not shorthand if it controls native-asset solvency.
  • Oracle changes should clear semantic checks before they clear activation checks. A market should not gain borrow authority just because a config transaction executed successfully.
  • Searchers monetize protocol-authored mispricing as fast as market-authored mispricing. Once Rho published fiction onchain, the exploit path was ordinary borrowing.
  • Fast containment matters, but it is downstream of a more basic requirement: a new-market rollout should not be able to silently rewrite an existing market’s truth root in the first place.

Why this incident matters

  • It is a compact, high-signal exemplar of oracle configuration failure where the error is neither decimal math nor missing quote legs, but simply binding the wrong asset to the wrong feed.
  • It preserves a sharp operational lesson for Compound-style and Aave-style lending deployments: market-launch scripts and oracle registries are balance-sheet code, even when the core lending contracts are behaving exactly as written.
  • It also shows how little time protocols get to react once a mispricing is published onchain; a searcher can convert a one-line config mistake into protocol bad debt before any human notices.

Internal linkages

Control surface