# Unlinked tophat retains linkedTreeRequests, can be rugged

Hats unlinkTopHatFromTree fails to clear linkedTreeRequests, letting a prior admin pre-stage a link request and later seize a supposedly sovereign tophat.

- Payout: Contest reward
- Severity: high
- Program: Hats
- Credited: cducrest-brainbot
- Disclosed: 2023-02-15
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-02-hats-judging/issues/35
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-hats%3AH-9
- Tags: domain:web3 impact:privesc kind:contest platform:sherlock sev:high tech:solidity technique:legacy-endpoint technique:source-review vuln:access-control vuln:business-logic

**Target:** Hats.sol tophat linking (requestLinkTopHatToTree/approveLinkTopHatToTree/unlinkTopHatFromTree)
**Root cause:** unlinkTopHatFromTree deletes linkedTreeAdmins but not linkedTreeRequests, so a pending link request created while still admin survives unlinking.
**Steps:**
1. TopHat is linked to Admin A
2. Admin A calls `requestLinkTopHatToTree(topHatDomain, attackerAddress)` while still admin; `_checkAdmin` passes and `linkedTreeRequests[domain]=attackerAddress`
3. Admin A calls `unlinkTopHatFromTree(topHatDomain)`; linkedTreeAdmins cleared but linkedTreeRequests persists
4. Later attackerAddress calls `approveLinkTopHatToTree(topHatDomain, attackerAddress)`; check `_newAdminHat == linkedTreeRequests[domain]` passes
5. `_linkTopHatToTree` executes, giving attacker admin control over the sovereign tophat
**How found:** Code reading of unlinkTopHatFromTree versus approveLinkTopHatToTree: noticed the request mapping is consumed only on approval, and unlink deletes only linkedTreeAdmins, leaving stale state that satisfies the LinkageNotRequested check later.
**Exploitation:** A malicious or colluding admin pre-registers a link request to an address they control before honoring an unlink, then later approves it to reclaim authority over the tophat without the tophat's consent.
**Insight:** When auditing link/unlink state machines, check that every teardown path clears all pending-request mappings, not just the active-link mapping; a leftover request is a pre-authorized capability that survives unlinking.
