# The owner of a LSP0ERC725Account can become the owner again after renouncing ownership

LSP0ERC725Account's two-step renounceOwnership only clears _pendingOwner on the first call, so an owner can re-set it via delegatecall and acceptOwnership after renouncing.

- Payout: Audit contest
- Severity: medium
- Program: LUKSO
- Found by: MiloTruck
- Disclosed: 2023-09-18
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2023-06-lukso#m-01
- Library page: https://bugbountylibrary.com/r/c4%3A2023-06-lukso%3AM-01
- Tags: area:web3 domain:web3 impact:privesc kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** LSP0ERC725Account / LSP14Ownable2Step ownership contract
**Root cause:** renounceOwnership() deletes _pendingOwner only during the first (initiation) call; the second call sets owner to address(0) but leaves _pendingOwner intact, so a previously staged pending owner can still acceptOwnership().
**Steps:**
1. Call `renounceOwnership()` to start the process; `_renounceOwnershipStartedAt` is set and `_pendingOwner` deleted.
2. Use `execute(4, address(implementation), 0, abi.encodeWithSelector(Implementation.setPendingOwner.selector, address(this)))` — a delegatecall writing slot 3 (`_pendingOwner`) to the owner's address.
3. Advance blocks past the confirmation period (`vm.roll(block.number + 200)`) and call `renounceOwnership()` again; owner becomes address(0), `_pendingOwner` remains.
4. Call `acceptOwnership()` to set owner back to the attacker.
**How found:** Code review of the two-step renounce flow: noticed _pendingOwner is deleted only in the first branch, then reasoned that execute()'s delegatecall could rewrite storage slot 3 between the two renounce calls.
**Exploitation:** Owner initiates renounce, uses the account's own execute() delegatecall to overwrite _pendingOwner, completes renouncement, then calls acceptOwnership() to regain control — enabling a rug after users trust the renounced state.
**Insight:** In two-step ownership/renounce designs, check that every terminal state clears all pending-owner state; and remember an account's own execute/delegatecall primitive can rewrite its own storage slots between multi-step flows.

