The claim() function is intended to verify eligibility and transfer the allocated token amount to the claimant exactly once per eligible address.
However, the function performs the external safeTransfer() call before writing any state that records the claim. This violates the Checks-Effects-Interactions (CEI) pattern: no effect (state change) is written between the checks and the external interaction. If the airdrop token is replaced with or upgraded to one that supports transfer hooks — such as ERC-777, which calls tokensReceived() on the recipient — a malicious recipient contract can re-enter claim() during the transfer, before any claimed state is recorded, and drain the contract recursively.
Likelihood:
The current token (USDC) is a standard ERC-20 with no transfer hooks, so reentrancy is not exploitable today — however, if the contract is redeployed with a hook-enabled token, the vulnerability becomes immediately exploitable without any code change
A future token upgrade or a deployer error that substitutes an ERC-777-compatible token activates the reentrancy path without any warning, since the contract contains no reentrancy guard
Impact:
A malicious recipient contract re-enters claim() during the token transfer callback, recursively draining the entire contract balance before any claimed state is written
The absence of a state update before the external call also means the fix for H-1 (s_hasClaimed[account] = true) must be placed before safeTransfer() to be effective — if it is placed after, the reentrancy window remains open even with H-1 patched
The reentrancy window exists because the contract's state is identical at the start of the first call and at the start of any reentrant call — there is nothing written to storage between the merkle proof check and the token transfer. A recipient contract that implements a transfer hook can therefore call claim() again mid-transfer and pass all checks a second time, repeating recursively until the contract is drained:
Move the s_hasClaimed state update (introduced as part of the H-1 fix) to before the safeTransfer() call, strictly following the Checks-Effects-Interactions order. This ensures that any reentrant call finds the account already marked as claimed and reverts immediately, closing the reentrancy window regardless of the token type used.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.