Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

[M-3] Function Selector Collisions in `RootProxy` contract Break Protocol Logic

Summary

Overlapping function selectors between branches cause unintended delegatecall routing.

Vulnerability Details

Affected Code:

// RootUpgrade.sol
function _addBranch(BranchUpgrade memory upgrade) internal {
for (uint i; i < upgrade.selectors.length; i++) {
selectorToBranch[upgrade.selectors[i]] = upgrade.branch; // No collision check
}
}

Proof of Concept:

// Test Setup
bytes4[] memory depositSelectors = getSelectors("deposit(uint256)");
BranchUpgrade memory legitBranch = BranchUpgrade({
branch: address(realDepositBranch),
action: BranchUpgradeAction.Add,
selectors: depositSelectors
});
// Attacker branch with same selector
bytes4[] memory maliciousSelectors = getSelectors("exploit()"); // Accidentally same as deposit
BranchUpgrade memory maliciousBranch = BranchUpgrade({
branch: address(maliciousBranch),
action: BranchUpgradeAction.Add,
selectors: maliciousSelectors
});
// Execute upgrades
upgradeBranches([legitBranch, maliciousBranch]);
// Test Call
proxy.deposit(100e18); // Actually calls exploit()

Exploit Validation:

Run test: forge test --match-test test_selectorCollision

Expected: Deposit increases balance

Actual: Funds stolen via exploit()

Impact

Critical Function Malfunction: High operational risk

Severity: High (CVSS 7.5)

Tools Used

Foundry fuzz testing

Recommendations

// Add selector uniqueness check
mapping(bytes4 => bool) public selectorRegistered;
function _addSelector(bytes4 selector) internal {
require(!selectorRegistered[selector], "Selector collision");
selectorRegistered[selector] = true;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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