Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: high
Valid

Incorrect Key Mapping in updateReferrerInfo Function Lead To Incorrect Referral Info Assignment

Summary

The updateReferrerInfo function is designed to update the referral information of a user, including the referrer address, referrer rate, and authority rate. The function validates the input parameters and stores the referral information in the referralInfoMap mapping. The ReferralInfo struct contains three arguments: referrer, referrerRate, and authorityRate.

Vulnerability Details

The key issue lies in the way the referral information is stored in the referralInfoMap. Instead of using the user’s address (the caller of the function) as the key, the _referrer address is used as the key. This leads to a situation where the referral information is incorrectly assigned to the referrer, rather than the user who is making the referral.

Code Snippet

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/storage/SystemConfigStorage.sol#L32

/// @dev user refferral info, detail see ReferralInfo.
mapping(address => ReferralInfo) public referralInfoMap;

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/SystemConfig.sol#L41-L80

function updateReferrerInfo(
address _referrer,
uint256 _referrerRate,
uint256 _authorityRate
) external {
if (_msgSender() == _referrer) {
revert InvalidReferrer(_referrer);
}
if (_referrer == address(0x0)) {
revert Errors.ZeroAddress();
}
if (_referrerRate < baseReferralRate) {
revert InvalidReferrerRate(_referrerRate);
}
uint256 referralExtraRate = referralExtraRateMap[_referrer];
uint256 totalRate = baseReferralRate + referralExtraRate;
if (totalRate > Constants.REFERRAL_RATE_DECIMAL_SCALER) {
revert InvalidTotalRate(totalRate);
}
if (_referrerRate + _authorityRate != totalRate) {
revert InvalidRate(_referrerRate, _authorityRate, totalRate);
}
@-> ReferralInfo storage referralInfo = referralInfoMap[_referrer];
referralInfo.referrer = _referrer;
referralInfo.referrerRate = _referrerRate;
referralInfo.authorityRate = _authorityRate;
emit UpdateReferrerInfo(
msg.sender,
_referrer,
_referrerRate,
_authorityRate
);
}

Impact

Incorrect Referral Info Assignment: When a user (e.g., Alice) calls updateReferrerInfo to set Bob as their referrer, the mapping incorrectly stores Bob's address as the key. As a result, when Alice or any other user checks Alice's referral info, the parameters (referrer, referrerRate, authorityRate) will be zero, meaning Alice's referral info is never properly set.

Unauthorized Referral Info Update: If Bob checks his referral info, he will see that the referrer, referrerRate, and authorityRate have been updated without his permission, as the mapping incorrectly assigns Alice's settings to him.

Proof Of Concept

  1. Alice call the updateReferrerInfo and make the bob as their account referrer.

  2. But the mapping set the referrer address as the key instead of the alice address.

  3. So that referral info stuct parameters for the alice is still zero .

  4. And the referral info for the bob is updated .

Proof Of Code

For testing the POC, run the following command:

forge test --mt test_IncorrectRefrralAssignment -vvvv
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.13;
import {PreMarketsTest} from "./PreMarkets.t.sol";
import {ISystemConfig} from "../src/interfaces/ISystemConfig.sol";
import {console2} from "forge-std/Test.sol";
contract ReferrerTest is PreMarketsTest {
address alice = address(0x123);
address bob = address(0x456);
function test_IncorrectRefrralAssignment() public {
// Owner set an additional referral rate for Bob (address 0x456).
vm.startPrank(user1);
systemConfig.updateReferralExtraRateMap(bob, 5);
vm.stopPrank();
vm.startPrank(alice);
address referrer = bob;
uint256 referrerRate = baseReferralRate;
uint256 authorityRate = 5;
systemConfig.updateReferrerInfo(bob, referrerRate, authorityRate);
// alice referral info parameters is always zero
systemConfig.getReferralInfo(alice);
// Bob refrralinfo is updated without its permission
systemConfig.getReferralInfo(bob);
vm.stopPrank();
}
}

Here are the logs of The POC

UpgradeableProxy::getReferralInfo(0x0000000000000000000000000000000000000123) [staticcall]
│ ├─ [7110] SystemConfig::getReferralInfo(0x0000000000000000000000000000000000000123) [delegatecall]
│ │ └─ ← [Return] ReferralInfo({ referrer: 0x0000000000000000000000000000000000000000, referrerRate: 0, authorityRate: 0 })
│ └─ ← [Return] ReferralInfo({ referrer: 0x0000000000000000000000000000000000000000, referrerRate: 0, authorityRate: 0 })
├─ [1631] UpgradeableProxy::getReferralInfo(0x0000000000000000000000000000000000000456) [staticcall]
│ ├─ [1110] SystemConfig::getReferralInfo(0x0000000000000000000000000000000000000456) [delegatecall]
│ │ └─ ← [Return] ReferralInfo({ referrer: 0x0000000000000000000000000000000000000456, referrerRate: 300000 [3e5], authorityRate: 5 })
│ └─ ← [Return] ReferralInfo({ referrer: 0x0000000000000000000000000000000000000456, referrerRate: 300000 [3e5], authorityRate: 5 })
├─ [0]

Tools Used

Foundry

Recommendations

The function should be modified to use the address of the user making the referral (the caller of the function) as the key in the referralInfoMap. This ensures that the referral information is correctly associated with the user who is performing the action.

function updateReferrerInfo(
address _referrer,
uint256 _referrerRate,
uint256 _authorityRate
) external {
if (_msgSender() == _referrer) {
revert InvalidReferrer(_referrer);
}
if (_referrer == address(0x0)) {
revert Errors.ZeroAddress();
}
if (_referrerRate < baseReferralRate) {
revert InvalidReferrerRate(_referrerRate);
}
uint256 referralExtraRate = referralExtraRateMap[_referrer];
uint256 totalRate = baseReferralRate + referralExtraRate;
if (totalRate > Constants.REFERRAL_RATE_DECIMAL_SCALER) {
revert InvalidTotalRate(totalRate);
}
if (_referrerRate + _authorityRate != totalRate) {
revert InvalidRate(_referrerRate, _authorityRate, totalRate);
}
-- ReferralInfo storage referralInfo = referralInfoMap[_referrer];
++ ReferralInfo storage referralInfo = referralInfoMap[msg.sender];
referralInfo.referrer = _referrer;
referralInfo.referrerRate = _referrerRate;
referralInfo.authorityRate = _authorityRate;
emit UpdateReferrerInfo(
msg.sender,
_referrer,
_referrerRate,
_authorityRate
);
}
Updates

Lead Judging Commences

0xnevi Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-SystemConfig-updateReferrerInfo-msgSender

Valid high severity. There are two impacts here due to the wrong setting of the `refferalInfoMap` mapping. 1. Wrong refferal info is always set, so the refferal will always be delegated to the refferer address instead of the caller 2. Anybody can arbitrarily change the referrer and referrer rate of any user, resulting in gaming of the refferal system I prefer #1500 description the most, be cause it seems to be the only issue although without a poc to fully describe all of the possible impacts

Support

FAQs

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