# `reportOutOfOrderValidatorExits` does not updates the heap order

reportOutOfOrderValidatorExits bumps exited count without re-heapifying, so stale heap max points to a zero-utilization operator and deallocation loop breaks early, blocking withdrawals.

- Payout: Contest reward
- Severity: high
- Program: Rio Network Core Protocol
- Credited: ComposableSecurity
- Disclosed: 2024-02-14
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-02-rio-network-core-protocol-judging/issues/131
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-7
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:high tech:solidity technique:incomplete-fix technique:source-review vuln:business-logic vuln:dos

**Target:** RioLRTOperatorRegistry / OperatorUtilizationHeap (Solidity restaking contract)
**Root cause:** reportOutOfOrderValidatorExits increments validatorDetails.exited but never updates or re-stores the utilization heap, so the persisted heap order no longer reflects actual utilization.
**Steps:**
1. Note heap is rebuilt from storage in getOperatorUtilizationHeapForETH assuming stored order is already sorted; no re-heapify on fetch.
2. Operators 1/2/3 have utilization 5/10/15 with cap 100; heap max = operator 3.
3. Operator 3 exits 15 validators out-of-order; owner calls `reportOutOfOrderValidatorExits(3, fromIndex, 15)` which sets exited=15, utilization=0, but heap storage unchanged.
4. User requests withdrawal; deallocateETHDeposits reads heap, getMax() returns operator 3.
5. activeDeposits = deposited - exited = 0, so `if (activeDeposits == 0) break;` exits loop with remainingDeposits > 0.
6. Withdrawal request fails despite other operators having active deposits.
**How found:** Code-reading: noticed getOperatorUtilizationHeapForETH trusts stored heap order without sorting, then compared reportOutOfOrderValidatorExits (mutates exited only) against deallocateETHDeposits' early-break on zero activeDeposits at heap max; built a 3-operator numeric example and a Foundry PoC showing min/max divergence.
**Exploitation:** No attacker capital needed; the owner's legitimate admin call to report out-of-order exits corrupts heap ordering, causing subsequent user withdrawal deallocations to revert/early-exit until heap is manually re-stored.
**Insight:** When a contract persists a heap/priority structure in storage and rebuilds it from storage assuming sorted order, audit every mutation path (admin setters, report functions) for missing re-heapify/store; a stale max pointing at a zero-value entry can trip early-break guards and DoS the whole queue.
