# NameWrapper: expired names behave unwrapped

Expired wrapped ENS names report ownerOf=0 but registry owner non-zero, so parents with CANNOT_CREATE_SUBDOMAIN fuse can re-create expired subdomains.

- Payout: Contest reward
- Severity: medium
- Program: ENS
- Credited: zzzitron
- Disclosed: 2023-05-26
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-11-ens-findings/issues/7
- Library page: https://bugbountylibrary.com/r/c4%3A2022-11-ens%3AM-02
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** NameWrapper.sol (canCallSetSubnodeOwner / setSubnodeRecord)
**Root cause:** On expiry NameWrapper.ownerOf returns address(0) but Registry.owner still points to NameWrapper, so the subnode is treated as unwrapped rather than unregistered; the CANNOT_CREATE_SUBDOMAIN check only applies to unregistered (registry owner zero) nodes.
**Steps:**
1. Wrap vitalik.eth via `nameWrapper.wrapETH2LD('vitalik', user1, CANNOT_UNWRAP, address(0))`
2. Create sub1 with `setSubnodeOwner(parent_node,'sub1',user2,PARENT_CANNOT_CONTROL,1700000000)`
3. Set parent fuse `setFuses(parent_node, CANNOT_CREATE_SUBDOMAIN)`
4. Confirm `setSubnodeRecord(parent_node,'sub1',...)` reverts with OperationProhibited while sub1 is live
5. `vm.warp(1700000001)` to expire sub1; observe `nameWrapper.ownerOf(sub1_node)==0` but `ens.owner(sub1_node)==address(nameWrapper)`
6. Call `setSubnodeRecord(parent_node,'sub1',address(3),address(11),10,0,0)` — succeeds despite CANNOT_CREATE_SUBDOMAIN
7. Contrast: creating fresh sub2 still reverts OperationProhibited
**How found:** Reading wrapper/README.md state definitions (Unregistered vs Unwrapped) and noticing expired names satisfy the Unwrapped criteria (NameWrapper.ownerOf=0, Registry.owner!=0), then testing whether the CANNOT_CREATE_SUBDOMAIN guard keys off registry owner and is therefore bypassed after expiry.
**Exploitation:** Parent owner of a name with CANNOT_CREATE_SUBDOMAIN burned waits for a subdomain to expire, then re-creates/reassigns that expired subdomain (owner and resolver) via setSubnodeRecord, defeating the fuse's guarantee that no new subdomains can be created.
**Insight:** When a contract defines state transitions (registered/unregistered/unwrapped) in docs, test whether expiry produces a hybrid state that falls through guards keyed on only one of the two owner sources; here the fuse check used Registry.owner only, so a stale non-zero registry owner skipped the guard.
