# Reentrancy revives consumed or burnt state

Callback re-mints, re-claims, or revives burnt ids before the completion flag is written

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

## How it works
A contract treats "already consumed" as final, but the flag or ownership record that marks consumption is written after an external call, or lives in a second contract that the callback can still change. During the callback the state still looks unconsumed, so the same id, claim, or fuse can be acted on again. The broken assumption is that a burnt/claimed marker is authoritative at the moment of the callback; in practice it is either not yet written or held in a parallel store that can diverge.

## Where it shows up
- Claim/mint functions taking an array of ids, with the claimed-set updated after minting or transferring value.
- Native ETH or token transfers before withdrawal/leave logic finalizes state [E2](https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-06.md).
- Parallel ownership stores (registry vs wrapper) where unwrap/re-wrap changes who controls a descendant [E1](https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AH-01.md).
- Fuse or permission flags enforced only while an object is wrapped, not while unwrapped [E1](https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AH-01.md).
- Bootstrap/initialization branches reachable mid-call that move pooled funds [E2](https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-06.md).
- Flash-loan callbacks that can re-enter a claim path before the pool balance is re-read [E3](https://bugbountylibrary.com/r/dhl%3A20240220-eggx.md).

## How to review
The invariant: once an id, claim, fuse, or withdrawal is consumed, no external call made during that transaction can observe or restore it as unconsumed. Check that the consumed marker is written before any external call, transfer, or callback, and that it lives in the same authoritative store the callback reads. For parallel-state designs, verify unwrap/re-wrap cannot change the owner of a descendant whose constraints are already burnt [E1](https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AH-01.md). For leave/unstake, confirm state is finalized before value leaves [E2](https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-06.md). For claim arrays, confirm each id is marked before minting and re-submission is rejected [E3](https://bugbountylibrary.com/r/dhl%3A20240220-eggx.md).

## Variants seen
- Re-claiming already-claimed NFT ids inside a flash callback to mint unbacked tokens [E3](https://bugbountylibrary.com/r/dhl%3A20240220-eggx.md).
- Native ETH transfer before withdrawal completion enabling reentrancy that drains treasury [E2](https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-06.md).
- Unwrap/re-wrap cycle reviving a child whose fuses were burnt, stealing the subnode [E1](https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AH-01.md).

## Impact and severity
High: unbacked minting and pool drain (~2 ETH) [E3](https://bugbountylibrary.com/r/dhl%3A20240220-eggx.md); treasury drain and halted checkpoints [E2](https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-06.md); subnode theft and bypass of burnt fuse constraints [E1](https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AH-01.md). Severity rises when the revived state gates fund movement or when the callback has ready exit liquidity.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AH-01.md
- E2: https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-06.md
- E3: https://bugbountylibrary.com/r/dhl%3A20240220-eggx.md
