Open code423n4 opened 1 year ago
minhquanym marked the issue as primary issue
minhquanym marked the issue as high quality report
CJ42 marked the issue as sponsor confirmed
trust1995 marked the issue as satisfactory
trust1995 marked the issue as selected for report
Interesting report <3
Lines of code
https://github.com/code-423n4/2023-06-lukso/blob/main/contracts/LSP0ERC725Account/LSP0ERC725AccountCore.sol#L560-L580
Vulnerability details
Bug Description
To transfer ownership of the
LSP0ERC725AccountCore
contract, the owner has to calltransferOwnership()
to nominate a pending owner. Afterwards, the pending owner must callacceptOwnership()
to become the new owner.When called by the owner,
transferOwnership()
executes the following logic:LSP0ERC725AccountCore.sol#L560-L580
The
currentOwner == owner()
check ensures thatpendingNewOwner
did not callacceptOwnership()
in theuniversalReceiver()
callback. However, a malicious contract can bypass this check by doing the following in itsuniversalReceiver()
function:acceptOwnership()
to gain ownership of the LSP0 account.execute()
to perform a delegate call that does either of the following:_owner
to the previous owner.This defeats the entire purpose of a two-step ownership transfer, which should ensure that the LSP0 account cannot be lost in a single call if the owner accidentally calls
transferOwnership()
with the wrong address.Impact
Should
transferOwnership()
be called with the wrong address, the address could potentially bypass the two-step ownership transfer process to destroy the LSP0 account in a single transaction.Proof of Concept
The following Foundry test demonstrates how an attacker can drain the LYX balance of an LSP0 account in a single transaction when set to the pending owner in
transferOwnership()
:Recommended Mitigation
Add a
inTransferOwnership
state variable, which ensures thatacceptOwnership()
cannot be called whiletransferOwnership()
is in execution, similar to a reentrancy guard:Assessed type
call/delegatecall