DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: high
Invalid

Unchecked Decoding of Referral::getReferrerAddress

Summary

The getReferrerAddress function does not validate the referralCode data before decoding it using abi.decode. This can lead to unexpected behavior or errors if referralCode does not contain a valid address.

Vulnerability Details

The function assumes that referralCode has a valid address format when isCustomReferralCode is false, which might not always be the case, leading to potential runtime errors.

Code snippet:

function getReferrerAddress(Data storage self) internal view returns (address referrer) {
if (!self.isCustomReferralCode) {
referrer = abi.decode(self.referralCode, (address));
} else {
referrer = CustomReferralConfiguration.load(string(self.referralCode)).referrer;
}
}

POC

Here’s a foundry fuzz test to ensure referralCode is valid before decoding it:

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;
import "forge-std/Test.sol";
import "../../src/perpetuals/leaves/Referral.sol";
contract ReferralTest is Test {
using Referral for Referral.Data;
// Define a mapping to hold the data struct for testing purposes
mapping(address => Referral.Data) testStorage;
function testValidReferralCodeDecoding(bytes memory referralCode) public {
address testAddress = address(this);
// Get the storage location for testing
Referral.Data storage data = testStorage[testAddress];
data.referralCode = referralCode;
data.isCustomReferralCode = false;
// Ensure it is address length
if (referralCode.length == 20) {
address referrer = data.getReferrerAddress();
require(referrer != address(0), "Decoded address is zero");
} else {
// Expect revert if referralCode length is not 20
vm.expectRevert();
// Add a require statement to ensure it reverts
require(referralCode.length == 20, "Invalid referral code length");
data.getReferrerAddress();
}
}
}
  • Run forge test --match-contract ReferralTest -vvv

  • Output: [FAIL. Reason: EvmError: Revert; counterexample: calldata=0x2c8ccc5a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000145bcbf976ac72b347c17b654d9c3a66964f940a8a000000000000000000000000 args=[0x5bcbf976ac72b347c17b654d9c3a66964f940a8a]] testValidReferralCodeDecoding(bytes) (runs: 5, μ: 37759, ~: 30735) Traces: [26382] ReferralTest::testValidReferralCodeDecoding(0x5bcbf976ac72b347c17b654d9c3a66964f940a8a) └─ ← [Revert] EvmError: Revert

Impact

  • Severity: High

  • Impact on the Protocol: Decoding incompatible or maliciously crafted referralCode can lead to runtime errors or potentially execute unintended logic, directly impacting contract functionality.

  • Likelihood of Exploitation: High. Without validation, it is highly probable that invalid referralCode data could lead to exploitation.

Tools Used

  • Manual code review

  • Foundry fuzz testing

Recommendations

Add validation logic to ensure referralCode is in a valid format before decoding it.

Example Fix:

function getReferrerAddress(Data storage self) internal view returns (address referrer) {
if (!self.isCustomReferralCode) {
+ require(self.referralCode.length == 20, "Invalid referral code length");
referrer = abi.decode(self.referralCode, (address));
} else {
referrer = CustomReferralConfiguration.load(string(self.referralCode)).referrer;
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
10 months ago
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.