# Reentrancy callback inflates accounting

Untrusted callback between a balance/fee read and its state update, letting the counterparty inflate payout

_Area: DeFi accounting and math bugs. Seen in 4 disclosed reports; latest 2023-05-18. Updated 2026-11-02._

## How it works
Accounting code reads a value (a fee, a reserve, a deposited total, a shared vault value), then makes an external call to an untrusted party, then either re-reads that value or writes state that depends on it. The assumption that breaks is that the value is stable across the external call. The counterparty — a royalty receiver, an ERC721 receiver, a malicious token, a swap target — runs code during the callback and changes the value or the state the contract is about to use, so the second read or the later write is computed against a manipulated baseline. The result is a payout, points balance or share count larger than the real assets backing it.

## Where it shows up
- A fee or price read once to compute a total, then re-read per item to execute transfers, with an external call in between [E1](https://bugbountylibrary.com/r/c4%3A2023-04-caviar%3AH-01.md).
- `_safeMint` / `onERC721Received` firing before a `totalDeposited` counter is incremented [E2](https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md).
- A `noReenter` guard on some entrypoints but not on permissionless accounting updaters [E2](https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md).
- Routers that compute multi-hop outputs upfront, then transfer tokens whose `transferFrom` can call back [E3](https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md).
- Functions that snapshot a shared pool/vault value, then perform an arbitrary-token swap [E4](https://bugbountylibrary.com/r/c4%3A2022-08-mimo%3AM-01.md).
- Any `_getRoyalty`, oracle read, or `balanceOf` used both before and after an untrusted call.

## How to review
Trace every external call (ETH send, token transfer, safeMint, arbitrary swap) and ask what state a callback could change. The invariant: any value used to compute a payout must be read once and held in a local, or the state it derives from must be updated before the external call, and re-entry into the same accounting path must be blocked. Check that guards cover every function that writes shared accounting state, not just the obvious entrypoints [E2](https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md). For routers, confirm reserves are locked or re-checked after transfers [E3](https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md). For rebalancers, confirm the value snapshot is committed before any swap executes [E4](https://bugbountylibrary.com/r/c4%3A2022-08-mimo%3AM-01.md).

## How finders spotted it
- Read `buy()` and noticed `_getRoyalty` called twice with an untrusted ETH refund between the calls [E1](https://bugbountylibrary.com/r/c4%3A2023-04-caviar%3AH-01.md).
- Compared `_safeMint` ordering against the `totalDeposited` update and saw `updateDistribution` lacked the `noReenter` modifier used elsewhere [E2](https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md).
- Noticed swap amounts computed before transfers with no reentrancy lock on reserves [E3](https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md).
- Saw swap data was fully arbitrary (malicious ERC20 reachable) and reasoned two vaults rebalancing into one would double-count [E4](https://bugbountylibrary.com/r/c4%3A2022-08-mimo%3AM-01.md).

## Variants seen
- Fee re-read after refund call inflates royalty total [E1](https://bugbountylibrary.com/r/c4%3A2023-04-caviar%3AH-01.md).
- safeMint hook re-enters accounting updater before deposit counter updates [E2](https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md).
- Stale reserves during multi-hop swap callback [E3](https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md).
- Shared vault value double-counted via reentrant second rebalance [E4](https://bugbountylibrary.com/r/c4%3A2022-08-mimo%3AM-01.md).

## Impact and severity
Drains pool balances [E1](https://bugbountylibrary.com/r/c4%3A2023-04-caviar%3AH-01.md), steals all staking rewards [E2](https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md), drains a WBNB/BURGER pair [E3](https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md), siphons vault funds [E4](https://bugbountylibrary.com/r/c4%3A2022-08-mimo%3AM-01.md). Impact scales with repeatability within one transaction [E1](https://bugbountylibrary.com/r/c4%3A2023-04-caviar%3AH-01.md) and with chaining flash loans and fake tokens to amplify profit [E3](https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md).

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-04-caviar%3AH-01.md
- E2: https://bugbountylibrary.com/r/c4%3A2022-01-xdefi%3AH-02.md
- E3: https://bugbountylibrary.com/r/dhl%3A20210527-burgerswap.md
- E4: https://bugbountylibrary.com/r/c4%3A2022-08-mimo%3AM-01.md
