The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: low
Invalid

Use Ownable2Step instead of Ownable

Summary

The contract LiquidationPoolManager inherits from Ownable, which allows the owner to transfer the ownership to any address without confirmation. This can lead to accidental or malicious loss of control over the contract.

Vulnerability Details

The Ownable contract has a function transferOwnership that allows the owner to change the owner address to any other address:

function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}

This function does not check if the new owner address is capable of receiving the ownership, or if the new owner address actually wants to accept the ownership. This can result in the following scenarios:

  • The owner makes a typo in the new owner address and transfers the ownership to an invalid or inaccessible address, effectively locking the contract forever.

  • The owner transfers the ownership to an address that is controlled by an attacker, who can then exploit the contract or harm the users.

  • The owner transfers the ownership to an address that is not aware of the ownership transfer, and does not know how to use the contract or manage the owner functions.

Impact

The impact of this vulnerability depends on the intention and capability of the new owner address. In the worst case, the contract can be rendered unusable or compromised by an attacker. In the best case, the contract can be recovered by the new owner if they are willing and able to accept the ownership.

Tools Used

Manul Finding

Recommendations

To prevent this vulnerability, we recommend using Ownable2Step or Ownable2StepUpgradeable instead of Ownable. These contracts require that the new owner address explicitly accept the ownership by calling a function acceptOwnership:

function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_pendingOwner = newOwner;
emit OwnershipTransferInitiated(_owner, newOwner);
}
function acceptOwnership() public virtual {
require(msg.sender == _pendingOwner, "Ownable: caller is not the pending owner");
emit OwnershipTransferred(_owner, _pendingOwner);
_owner = _pendingOwner;
_pendingOwner = address(0);
}

This way, the ownership transfer is a two-step process that ensures that the new owner address is valid and willing to take over the contract. This also allows the current owner to cancel the transfer if they change their mind or make a mistake.

Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

single-step-ownership

informational/invalid

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.