AirDropper

AI First Flight #5
Beginner FriendlyDeFiFoundry
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Anyone can call claim() for any eligible address enabling front-running

Summary

claim() allows any caller to submit a claim for any eligible address. Anyone with a valid proof can front-run claims and drain funds.

Vulnerability Details

In MerkleAirdrop.sol:30, claim takes account as a parameter, not msg.sender:

function claim(address account, uint256 amount, bytes32[] calldata merkleProof) external payable {

The Merkle proof validates account, not msg.sender. Proofs are deterministic from the tree inputs, so anyone who knows them can construct valid proofs. Combined with no double-claim protection, an attacker can: (1) watch mempool for claim txs, extract proofs, (2) call claim repeatedly for all eligible addresses, draining the entire balance.

Impact

HIGH — Once a single claim tx enters the mempool, its proof is public. An attacker extracts it, replays for all addresses, and drains the airdrop combined with the no-double-claim bug.

Proof of Concept

function testAnyoneCanClaim() public {
address attacker = makeAddr("attacker");
vm.deal(attacker, 1 ether);
uint256 balBefore = token.balanceOf(collectorOne);
vm.prank(attacker);
airdrop.claim{value: 1e9}(collectorOne, amountToCollect, proof);
assertEq(token.balanceOf(collectorOne) - balBefore, amountToCollect);
}

Recommended Fix

Require msg.sender == account or use EIP-712 signature-based claiming.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 19 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!