# Claim airdrop repeatedly

validate() only checks amount==0, so after claimExact() zeroes the balance, re-validating resets claimed and lets the airdrop be claimed repeatedly.

- Payout: Audit contest
- Severity: high
- Program: Boot Finance
- Found by: gpersoon
- Disclosed: 2022-01-21
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-11-bootfinance-findings/issues/129
- Library page: https://bugbountylibrary.com/r/c4%3A2021-11-bootfinance%3AH-05
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** AirdropDistribution.sol airdrop vesting contract
**Root cause:** validate() gates on airdrop[msg.sender].amount == 0 instead of the validated[] flag, so a fully-claimed user (amount now 0) can re-run validate(), which overwrites their record and resets claimed to 0.
**Steps:**
1. Call `claimExact(claimable)` to drain the final portion so `airdrop[msg.sender].amount` becomes 0.
2. Call `validate()` again; the `require(airdrop[msg.sender].amount == 0)` check passes.
3. validate() overwrites `airdrop[msg.sender]` with fresh values and sets `claimed = 0`.
4. Call `claimExact()` again to claim the airdrop anew, repeating while the contract holds tokens.
**How found:** Code reading: noticed validate() checks amount==0 rather than the validated[] flag, and that claimExact() sets amount to 0 on the last claim, making the two functions compose into a reset.
**Exploitation:** Attacker with a validated airdrop claims the full amount via claimExact(), then re-invokes validate() to reset their claimed counter and re-claim, draining tokens from the distribution contract.
**Insight:** When a guard checks a mutable balance that a sibling function zeroes out, the guard can be re-satisfied; look for state flags (validated[]) that are written but never read on entry.
