Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: low
Invalid

Anyone can claim rewards on behalf of anyone

Summary

The FeeCollector::claimRewards lacks restriction on who can call the function, allowing anyone to claim rewards on behalf of someone else.

Vulnerability Details

The FeeCollector::claimRewards is designed to ensure users can claim their rewards:-

function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
if (user == address(0)) revert InvalidAddress();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
// Reset user rewards before transfer
userRewards[user] = totalDistributed;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}

However, as we can see there is no restriction on who can call this function on behalf of, hence allowing anyone to claim rewards for someone else who is not even willing to claim.

Impact

  1. This is sub-optimal as users who would not want to claim rewards for a certain time period would be forced claimed.

  2. Not claiming rewards can also be seen as a way to save funds for future usecase or simply to show trust on the protocol.

Proof of Concept

Add the below test case inside the FeeCollector.test.js file:

describe("Reward Claim Issue", async function() {
it("should allow anyone to claim rewards for anyone", async function () {
await feeCollector.connect(owner).distributeCollectedFees();
await time.increase(WEEK);
const initialBalance = await raacToken.balanceOf(user1.address);
// Create a random signer
const [userRandom] = await ethers.getSigners();
// Claim rewards for user1 using random address
await feeCollector.connect(userRandom).claimRewards(user1.address);
expect(await raacToken.balanceOf(user1.address)).to.be.gt(initialBalance);
});
})

As we can observe, a random address just claimed rewards for a user.

Tools Used

Manual Review

Hardhat

Recommendations

It is recommended to implement a msg.sender check on claims:

- function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
+ function claimRewards() external override nonReentrant whenNotPaused returns (uint256) {
- if (user == address(0)) revert InvalidAddress();
+ address user = msg.sender;
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
// Reset user rewards before transfer
userRewards[user] = totalDistributed;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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.