Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Lack of a claim verification mechanism in the function `MerkleAirdrop::claim` results in the USDC protocol balance draining

Summary

The claim function in the MerkleAirdrop contract enables eligible users to claim their 25 USDC airdrop. However, the current implementation of the MerkleAirdrop.sol contract lacks a mechanism to prevent users from claiming the airdrop multiple times, which could lead to draining the contract's USDC balance.

Vulnerability Details

The vulnerability arises due to the absence of restrictions on how many times an eligible user can call the MerkleAirdrop::claim function to collect the airdrop. This allows an attacker to call the function multiple times and claim the USDC airdrop intended for other users as well.

Proof of Code

Add the following test to the MerkleAirdropTest.t.sol test suite.

function testUsersCanClaimMultipleTimes() public {
uint256 startingBalance = token.balanceOf(collectorOne);
vm.deal(collectorOne, airdrop.getFee() * 4);
vm.startPrank(collectorOne);
for (uint i = 0; i < 4; i++) {
airdrop.claim{value: airdrop.getFee()}(
collectorOne,
amountToCollect,
proof
);
}
vm.stopPrank();
uint256 endingBalance = token.balanceOf(collectorOne);
assertEq(endingBalance - startingBalance, amountToSend);
}

Impact

This vulnerability allows an eligible user to claim all the USDC tokens present in the protocol, potentially draining the protocol's USDC balance.

Tools Used

  • Manual code review

  • Foundry

Recommendations

Add a verification mechanism to make sure that an user can claim only its airdrop. An example is the following:

Code
+ error MerkleAirdrop__AirdropAlreadyClaimed();
+ mapping(address => bool) private claimed; // Track claimed status
...
function claim(address account, uint256 amount, bytes32[] calldata merkleProof) external payable {
if (msg.value != FEE) {
revert MerkleAirdrop__InvalidFeeAmount();
}
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(account, amount))));
if (!MerkleProof.verify(merkleProof, i_merkleRoot, leaf)) {
revert MerkleAirdrop__InvalidProof();
}
+ if (claimed[account]) { // Check if user already claimed
+ revert MerkleAirdrop__AirdropAlreadyClaimed();
+ }
+ claimed[account] = true; // Mark user as claimed
emit Claimed(account, amount);
i_airdropToken.safeTransfer(account, amount);
}
Updates

Lead Judging Commences

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

multi-claim-airdrop

Support

FAQs

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