# Extcodesize contract-check bypass

Code-existence checks using extcodesize or codehash that a constructor, selfdestruct, or dust transfer defeats

_Area: Smart contract access control and control flow. Seen in 5 disclosed reports; latest 2026-06-09. Updated 2026-10-23._

## How it works
A contract decides "is this address a contract?" by reading its code size or code hash. That reading is not a stable property of the address: during construction the code is not yet deployed, after selfdestruct it is gone, and a plain account with a balance but no code returns a non-zero codehash (keccak256("")). So the check answers "does code exist right now", while the code assumes "this address is permanently a contract" or "this address is permanently empty". Any attacker who can control timing (constructor, selfdestruct in the same transaction, CREATE2 redeploy) or who can dust a predicted address flips the answer.

## Where it shows up
- `extcodesize(x) > 0` or `== 0` used as a contract/EOA gate, blocklist, or "no contracts" deposit guard [E2](https://bugbountylibrary.com/r/sherlock%3A2024-11-teller-finance-update%3AH-2.md)[E3](https://bugbountylibrary.com/r/dhl%3A20260609-novabox.md)[E4](https://bugbountylibrary.com/r/c4%3A2022-08-fiatdao%3AM-02.md)
- `x.codehash != bytes32(0)` used as a "is this deployed" existence check [E1](https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md)
- CREATE2 predicted-address guards that assume the address stays empty until deployment [E1](https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md)
- try/catch around a call to an address whose code can vanish in the same transaction [E2](https://bugbountylibrary.com/r/sherlock%3A2024-11-teller-finance-update%3AH-2.md)
- Guards that skip state initialization (checkpoints, reward debt, timestamps) on the bypassed path [E3](https://bugbountylibrary.com/r/dhl%3A20260609-novabox.md)

## How to review
Identify every place code presence is inferred from extcodesize or codehash, then ask what the code does with that answer. The invariant that must hold: the decision must not depend on code presence at call time. Use `x.code.length != 0` only where a transient answer is acceptable, and never as an existence or identity check [E1](https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md). For blocklists and allowlists, key on the address itself, not on whether it currently has code [E4](https://bugbountylibrary.com/r/c4%3A2022-08-fiatdao%3AM-02.md). For deposit/reward paths, verify that every admitted address initializes its checkpoints regardless of how it passed the guard [E3](https://bugbountylibrary.com/r/dhl%3A20260609-novabox.md). For callbacks, confirm a codeless target cannot make a required path revert, and that try/catch actually swallows the failure [E2](https://bugbountylibrary.com/r/sherlock%3A2024-11-teller-finance-update%3AH-2.md).

## Variants seen
- codehash != 0 existence check defeated by a 1 wei transfer to an empty address [E1](https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md)
- CREATE2 address guard griefed by dusting the predicted address [E1](https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md)
- extcodesize gate bypassed from a constructor, admitting an uninitialized depositor [E3](https://bugbountylibrary.com/r/dhl%3A20260609-novabox.md)
- selfdestruct plus CREATE2 redeploy to evade a blocklist [E4](https://bugbountylibrary.com/r/c4%3A2022-08-fiatdao%3AM-02.md)
- selfdestruct of a listener in the same transaction so a try/catch repay callback reverts [E2](https://bugbountylibrary.com/r/sherlock%3A2024-11-teller-finance-update%3AH-2.md)

## Impact and severity
Outcomes ranged from bricked deployments and skipped escrow [E1](https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md), to blocked repayment enabling collateral seizure [E2](https://bugbountylibrary.com/r/sherlock%3A2024-11-teller-finance-update%3AH-2.md), to a 56.73 ETH dividend drain [E3](https://bugbountylibrary.com/r/dhl%3A20260609-novabox.md), to persistent blocklist evasion [E4](https://bugbountylibrary.com/r/c4%3A2022-08-fiatdao%3AM-02.md). Severity rises when the bypassed check also gates fund movement or state initialization, and when the attacker controls timing within one transaction.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-10-wildcat%3AH-02.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-11-teller-finance-update%3AH-2.md
- E3: https://bugbountylibrary.com/r/dhl%3A20260609-novabox.md
- E4: https://bugbountylibrary.com/r/c4%3A2022-08-fiatdao%3AM-02.md
