# Privileged path pre-occupies migration state

Does another privileged path write the token ID, allowance, or allowlist entry a migration or transfer assumes is free?

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

## How it works
A migration or transfer path assumes some state is still free: a token ID not yet minted, an allowance at zero, an allowlist that already covers the counterparty. A second, privileged path writes that same state first. The migration then hits a duplicate mint or a rejected transfer and reverts. The broken assumption is "no one else has touched this yet." Whether the block is permanent depends on the state: a pre-minted token ID cannot be undone unless it can be burned, while a residual allowance or a missing allowlist entry can be cleared or updated.

## Where it shows up
- Migration code that mints a token ID derived from legacy state, with no check that the ID is still unclaimed.
- Privileged mint functions (whitelisted creators, admins) that skip the uniqueness check the migration relies on.
- ERC721/ERC20 transfer hooks overridden with a protocol-contract allowlist; check every contract that must custody the token.
- Legacy `safeApprove` where caller-supplied calldata goes to a fixed approved target and can leave a non-zero residual allowance.
- Batch loops (batchMigrateProfiles, performUpkeep) where one reverting item blocks the whole batch.

## How to review
For each migration or transfer path, list every other path that can write the same state (token ID, allowance, allowlist entry). The invariant: before migration mints or transfers, the target state must be provably untouched, or the migration must handle the already-taken case. Concretely: for mints, confirm every mint path enforces the same uniqueness check, or that the migration can skip/burn a taken ID; for allowlists, enumerate all protocol contracts that must hold the token and confirm each is permitted; for approvals, confirm the approved target cannot leave residual allowance that makes the next approval revert.

## Variants seen
- Whitelisted creator mints a handle matching an unmigrated V1 profile; migration's mint reverts, blocking that profile's migration [E3](https://bugbountylibrary.com/r/c4%3A2023-07-lens%3AM-05.md).
- NFT receipt overrides transferFrom with a contract allowlist that omits BuyOrder, so selling to a buy order always reverts until the allowlist is updated [E2](https://bugbountylibrary.com/r/sherlock%3A2024-10-debita%3AH-4.md).
- Caller-supplied txData leaves 1 wei allowance; legacy safeApprove reverts on non-zero-to-non-zero, blocking swaps for that token until the residual is consumed [E1](https://bugbountylibrary.com/r/sherlock%3A2024-11-oku%3AM-4.md).

## Impact and severity
In all three the affected asset or path becomes unusable: migration blocked [E3](https://bugbountylibrary.com/r/c4%3A2023-07-lens%3AM-05.md), limit orders broken [E2](https://bugbountylibrary.com/r/sherlock%3A2024-10-debita%3AH-4.md), swaps blocked for a token [E1](https://bugbountylibrary.com/r/sherlock%3A2024-11-oku%3AM-4.md). Severity is medium-to-high. It worsens when the blocking state cannot be cleared (a pre-minted ID with no burn path) and when a batch loop turns one blocked item into a whole-function denial of service [E3](https://bugbountylibrary.com/r/c4%3A2023-07-lens%3AM-05.md). Note the blocking state may be created accidentally by a privileged actor [E3](https://bugbountylibrary.com/r/c4%3A2023-07-lens%3AM-05.md) or deliberately via caller-controlled input [E1](https://bugbountylibrary.com/r/sherlock%3A2024-11-oku%3AM-4.md), so do not assume it requires an attacker.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2024-11-oku%3AM-4.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-10-debita%3AH-4.md
- E3: https://bugbountylibrary.com/r/c4%3A2023-07-lens%3AM-05.md
