# RemoveStakes and RemoveDelegateStakes silently handle errors in EndBlocker

Allora's EndBlocker sends unstaked funds before updating stake state; a mid-update error leaves funds paid but stake still queued, enabling double withdrawal.

- Payout: Contest reward
- Severity: high
- Program: Allora
- Credited: imsrybr0
- Disclosed: 2024-06-24
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-06-allora-judging/issues/55
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-06-allora%3AH-7
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:go technique:source-review vuln:accounting-error vuln:business-logic vuln:race-condition

**Target:** Cosmos SDK emissions module EndBlocker stake removal
**Root cause:** RemoveStakes/RemoveDelegateStakes send coins to the staker first, then call RemoveReputerStake/RemoveDelegateStake; if the state update errors, the loop continues, leaving partial state and the removal still queued.
**Steps:**
1. Queue a stake removal via RemoveStake/RemoveDelegateStake with a delay.
2. At the target block, EndBlocker calls RemoveStakes/RemoveDelegateStakes.
3. SendCoinsFromModuleToAccount succeeds, paying the staker.
4. RemoveReputerStake/RemoveDelegateStake errors partway (e.g. integer underflow check or a Set/Delete failure), leaving some state written and the removal not deleted.
5. Loop continues; staker keeps funds and can re-queue the same removal for another payout.
**How found:** Code review of EndBlocker ordering: noticed SendCoins precedes state mutation and that errors are logged and skipped rather than reverting the whole removal.
**Exploitation:** Attacker queues a stake removal; if the keeper state update reverts after the coin transfer, the removal entry persists while funds are already sent, allowing repeated re-queue and withdrawal of the same stake.
**Insight:** In Cosmos EndBlockers, any external transfer before state mutation is a double-spend vector because errors are swallowed per-item; check ordering of bank sends vs. keeper writes and whether a failed write leaves the queue entry intact.
