HardhatFoundry
30,000 USDC
View results
Submission Details
Severity: high
Invalid

Improper Storage Slot Usage Will Lead To Storage Collision and Upgrade Failures

Summary

The upgradeToAndCall|function is intended to upgrade the proxy's implementation to a new address and optionally call a function on the new implementation. However, there is an issue related to storage manipulation. Specifically, the contract uses the contract's address as a storage slot identifier to store the new implementation address.This will lead to storage collision, resulting in unpredictable behavior, overwriting of critical state variables, and failure of the upgrade process.

Vulnerability Details

function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual override onlyEntryPointOrSelf {
require(newImplementation != address(0), InvalidImplementationAddress());
bool res;
assembly {
res := gt(extcodesize(newImplementation), 0)
}
require(res, InvalidImplementationAddress());
// update the address() storage slot as well.
assembly {
sstore(address(), newImplementation)
}
UUPSUpgradeable.upgradeToAndCall(newImplementation, data);
}

Incorrect Storage Slot Update:

assembly {
sstore(address(), newImplementation)
}

The line sstore(address(), newImplementation) store's the new implementation address in the storage slot corresponding to the address of the contract. This is incorrect and dangerous for the following reasons:

Misuse of Storage Slots: The address()function call does not return a valid storage slot. Storage slots should be explicitly defined to avoid overwriting critical data.

Overwrite of Important Data: This could inadvertently overwrite important contract state variables, leading to unpredictable behavior or complete loss of functionality.

Tools Used

Manual Review

Recommendations

Use a predefined storage slot for the implementation address, typically defined using a constant hash as per the EIP-1967 standard.

bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

Update the implementation address using the correct storage slot.

assembly {
sstore(\_IMPLEMENTATION\_SLOT, newImplementation)
}
function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual override onlyEntryPointOrSelf {
require(newImplementation != address(0), InvalidImplementationAddress());
bool res;
assembly {e
res := gt(extcodesize(newImplementation), 0)
}
require(res, InvalidImplementationAddress());
// Update the implementation address in the correct storage slot
assembly {
sstore(\_IMPLEMENTATION\_SLOT, newImplementation)
}
// Call the new implementation
UUPSUpgradeable.upgradeToAndCall(newImplementation, data);
}

}

Updates

Lead Judging Commences

0xnevi Lead Judge
12 months ago
0xnevi Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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