Flow

Sablier
FoundryDeFi
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

Implement Two-Step Admin Transfer Mechanism for Enhanced Security in Adminable Contract

Summary

In the Adminable contract, the transferAdmin function allows for an immediate transfer of the admin role to a new address. However, using a two-step admin transfer pattern is often recommended to prevent accidental or malicious immediate transfers. OpenZeppelin’s Ownable contract implements a robust two-step ownership transfer mechanism that could be adapted for this Adminable contract.

Vulnerability Details

The transferAdmin function in Adminable uses an immediate transfer of admin rights, which poses a risk if an incorrect address is set as the new admin or if a transaction is accidentally executed. A two-step admin transfer mechanism, such as the one in OpenZeppelin's Ownable, could prevent unintended transfers by requiring the new admin to explicitly accept the role.

Impact

A two-step transfer process would reduce the risk of accidental admin transfers and offer more secure and deliberate role management.

Tools Used

Manual Review

Recommendations

Implementing a Two-Step Admin Transfer Mechanism

Use Openzeppelin's Ownable2Step contract: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable2Step.sol

  1. Add Pending Admin State Variable: Introduce a pendingAdmin address state variable to store the address of the new admin until they accept the role.

  2. Modify transferAdmin to Set Pending Admin: Update the transferAdmin function so that it sets the pendingAdmin instead of transferring immediately.

  3. Create an acceptAdmin Function: Add an acceptAdmin function that the pending admin must call to complete the transfer.

  4. Use OpenZeppelin’s Pattern as Reference: OpenZeppelin’s Ownable contract provides a well-tested pattern that could be adapted here.

/// @notice Initiates transfer of admin role to `newAdmin`. New admin must call `acceptAdmin` to complete.
function transferAdmin(address newAdmin) public onlyAdmin {
pendingAdmin = newAdmin;
emit IAdminable.AdminTransferInitiated(admin, newAdmin);
}
/// @notice Completes the transfer of admin role by the new admin.
function acceptAdmin() public {
require(msg.sender == pendingAdmin, "Only pending admin can accept");
emit IAdminable.AdminTransferred(admin, pendingAdmin);
admin = pendingAdmin;
pendingAdmin = address(0);
}

This two-step mechanism requires both the current and new admin to confirm the transfer, reducing the chance of accidental or malicious admin changes.

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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