DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: low
Valid

Storage Collision Due to Lack of Validation for CustomReferralConfiguration::Load function

Summary

The load function computes a storage slot based on the CUSTOM_REFERRAL_CONFIGURATION_DOMAIN and the customReferralCode input. If there are other contracts or libraries using a similar storage slot determination mechanism, this could lead to unexpected storage collisions.

Vulnerability Details

Code snippet affected:

function load(string memory customReferralCode)
internal
pure
returns (Data storage customReferralConfigurationTestnet)
{
bytes32 slot = keccak256(abi.encode(CUSTOM_REFERRAL_CONFIGURATION_DOMAIN, customReferralCode));
assembly {
customReferralConfigurationTestnet.slot := slot
}
}

Proof of concept

Copy this code to test folder:

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "forge-std/Test.sol";
import "../../src/perpetuals/leaves/CustomReferralConfiguration.sol";
contract FuzzCustomReferralConfigurationTest is Test {
using CustomReferralConfiguration for *;
struct Data {
address referrer;
}
function testStorageCollision(bytes32 uniqueSlot, address referrer1, address referrer2) public {
// Ensure uniqueSlot is non-zero
require(uniqueSlot != bytes32(0), "uniqueSlot cannot be zero");
// Store data in a custom slot outside the library function
Data storage data;
assembly {
data.slot := uniqueSlot
}
data.referrer = referrer1;
// Call load from library with a different input that would match the above slot
string memory randomString = string(abi.encodePacked(uniqueSlot));
CustomReferralConfiguration.Data storage refData = CustomReferralConfiguration.load(randomString);
refData.referrer = referrer2;
assertEq(data.referrer, referrer1, "Expected distinct address in Data");
assertEq(refData.referrer, referrer2, "Expected distinct address in Custom Referral Data");
}
  • Run forge test --match-contract CustomReferralConfigurationTest -vvv

Output when running:
[FAIL. Reason: revert: uniqueSlot cannot be zero; counterexample: calldata=0xc9164d150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018b0000000000000000000000000000000000000000000000000000000000001322 args=[0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000000000000000018b, 0x0000000000000000000000000000000000001322]] testStorageCollision(bytes32,address,address) (runs: 1, μ: 50252, ~: 50252)

The error message indicates that the test reverted with the message "uniqueSlot cannot be zero". This suggests that the function being tested does not handle the case where uniqueSlot is zero correctly.

Impact

High
Storage collisions can lead to severe consequences including data corruption and critical vulnerabilities in the contract. Specifically, if the load function generates a slot that overlaps with slots used by other contracts or libraries, it could inadvertently overwrite important data. This could lead to unpredictable behavior, loss of funds, or even complete failure of the contract's logic. In environments with multiple contracts sharing a storage namespace, the risk of such collisions significantly amplifies the potential impact.

Tools Used

Manual review and Foundry

Recommendations

Implement a more robust storage slot computation or add additional unique identifiers as described in the initial suggestion.

Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Storage computation formula of ERC7201 is not followed. ERC7201 non compliance.

Support

FAQs

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

Give us feedback!