# Claim reentrancy skews accounting totals

Caller-supplied contracts or ETH callbacks that reenter claim/repay before totals and rates update

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2024-11-11. Updated 2026-10-24._

## How it works
Accounting code assumes a function's intermediate state is invisible to outsiders. When a claim, refund, or repay hands control to a caller-controlled contract (a fake market, pair, or ETH `receive()`) before it finishes updating totals, the callback sees a half-updated ledger. Cash or reward balances have moved but `totalBorrows`, `totalSupply`, or reward indexes have not, so the derived exchange rate or reward balance is wrong. The attacker acts on that wrong number inside the same transaction.

## Where it shows up
- Reward-claim or repay functions that call out to a caller-supplied address (pair, market, token) before writing totals.
- A registration path that accepts arbitrary pools/markets, after which harvest trusts that pool's self-reported token list and reward indexes [E1](https://bugbountylibrary.com/r/dhl%3A20240903-penpiexyzio.md).
- ETH refunds via `receive()`/`fallback` mid-function, before `totalBorrows` is reduced [E3](https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md).
- Exchange rate computed from `getCashPrior()` while a callback is still pending [E3](https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md).
- Claim functions taking caller-controlled pair/reward ids with no reentrancy guard [E2](https://bugbountylibrary.com/r/dhl%3A20241111-deltaprime.md).

## How to review
Find every external call in claim/repay/refund paths and ask what ledger state is stale at that point. The invariant: by the time control leaves the contract, cash, `totalBorrows`, `totalSupply`, and reward indexes must be mutually consistent, and no caller-supplied contract may observe or act on an inconsistent snapshot. Check that registered markets/pairs are validated against a trusted registry, not trusted for self-reported token lists or indexes [E1](https://bugbountylibrary.com/r/dhl%3A20240903-penpiexyzio.md). Confirm a reentrancy guard or checks-effects-interactions ordering covers the whole claim, including ETH refunds [E2](https://bugbountylibrary.com/r/dhl%3A20241111-deltaprime.md)[E3](https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md). For each callback, determine whether it can observe totals (cash, borrows) or only reward indexes; the fix differs.

## Variants seen
- Fake registered market inflates rewards via reentrant claim [E1](https://bugbountylibrary.com/r/dhl%3A20240903-penpiexyzio.md).
- Malicious pair reenters `claimReward` to shift collateral/debt accounting before solvency is checked [E2](https://bugbountylibrary.com/r/dhl%3A20241111-deltaprime.md).
- `repayBorrowBehalf` refund callback inflates exchange rate before `totalBorrows` drops [E3](https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md).

## Impact and severity
Critical: drains of ~$27M [E1](https://bugbountylibrary.com/r/dhl%3A20240903-penpiexyzio.md), ~$4.75M [E2](https://bugbountylibrary.com/r/dhl%3A20241111-deltaprime.md), and 350K [E3](https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md). Worse when the manipulated rate lets the attacker borrow far beyond collateral [E3](https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md), and when a flash loan funds the attack in one transaction [E2](https://bugbountylibrary.com/r/dhl%3A20241111-deltaprime.md). Severity rises with the size of pools reachable in one transaction.

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20240903-penpiexyzio.md
- E2: https://bugbountylibrary.com/r/dhl%3A20241111-deltaprime.md
- E3: https://bugbountylibrary.com/r/dhl%3A20240412-sumermoney.md
