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 10 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.