# Reentrancy lock nesting and missing guards

Callback re-entering a locked caller, or unguarded multicall sweeping shared balance to msg.sender

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2024-01-16. Updated 2026-10-24._

## How it works
Two distinct failures. First, lock nesting: an external contract (e.g. a VRF coordinator) holds its `nonReentrant` lock while invoking your `fulfill*` callback; if your handler calls back into that same contract, the nested call reverts and the flow never completes [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AM-1.md). Second, a guard is absent or ineffective: a multicall entrypoint has no reentrancy check, or a helper named like a revert only moves funds and does not abort the local call, so execution continues past a step that should have stopped it [E1](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md)[E2](https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AM-07.md). In E2 the drain itself is a balance sweep to `msg.sender`; reentrancy is only the trigger.

## Where it shows up
- A `fulfill*`/callback handler that calls back into the oracle or coordinator mid-callback [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AM-1.md).
- Multicall/virtual-account entrypoints with no reentrancy guard, where a later sub-call depends on state set by an earlier one [E1](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md)[E2](https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AM-07.md).
- Helpers named `forceRevert`/`_revert` that withdraw or move funds but do not actually revert the local call [E1](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md).
- A final step that sweeps the contract's whole token balance to `msg.sender`, combined with callback-capable tokens (ERC777/ERC677) or an arbitrary `to` recipient [E2](https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AM-07.md).
- State flags (e.g. `initialGas`) cleared only inside a pay/gas step, so skipping that step leaves them set [E1](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md).

## How to review
For each callback, ask: does the handler re-enter the contract currently executing it? Invariant: a callback must not call back into a function the caller holds locked. For multicalls, confirm each sub-call is independently safe and that no step sweeps a shared balance to a caller-controlled address. Any helper meant to abort must actually revert, and one-shot flags must be cleared on every path.

## Variants seen
- Auto-start of the next round inside `fulfillRandomWords` re-enters the VRF coordinator's `nonReentrant` request and reverts [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AM-1.md).
- `_forceRevert` withdraws the gas budget without reverting; a later `callOut` skips gas payment, freezing the budget [E1](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md).
- Unguarded `execute` multicall unwraps the full WETH balance to `msg.sender`; an ERC777 hook re-enters and claims it [E2](https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AM-07.md).

## Impact and severity
Cross-chain messaging DoS and frozen gas budget [E1](https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md); theft of native tokens owed to another user [E2](https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AM-07.md); lottery rounds that never conclude [E3](https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AM-1.md). Severity rises when the locked path is the only way to progress (permanent DoS) or when a shared balance is swept to an attacker-chosen recipient.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-23.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AM-07.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2024-01-looksrare%3AM-1.md
