# GFOX: unprotected setMerkleRoot enables forged merkle claim

GFOX claim contract let anyone call setMerkleRoot, so attacker set their own root and claimed 1.78e27 GFOX tokens worth ~330K USD.

- Payout: Real-world hack
- Severity: high
- Program: GFOX
- Analysis by: DeFiHackLabs
- Disclosed: 2024-05-10
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-05/GFOX_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240510-gfox
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Merkle airdrop claim contract on Ethereum mainnet
**Root cause:** setMerkleRoot() had no access control, allowing any caller to replace the claim merkle root with an attacker-controlled one.
**Steps:**
1. Fork mainnet at block 19835924
2. Compute root = keccak256(abi.encodePacked(address(this), amount)) with amount=1780453099185000000000000000
3. Call `victim.setMerkleRoot(root)` on 0x11A4a5733237082a6C08772927CE0a2B5f8A86B6
4. Call `victim.claim(address(this), amount, new bytes32[](0))` with empty proof
5. Receive GFOX tokens to attacker contract
**How found:** Likely source review of the claim contract revealing setMerkleRoot lacked onlyOwner/role checks, making the merkle proof verification trivially bypassable.
**Exploitation:** Attacker overwrote the merkle root with a single-leaf root matching their own address and chosen amount, then claimed with an empty proof, draining GFOX tokens from the vulnerable contract (~330K USD).
**Insight:** On merkle-claim airdrop contracts, always check who can write the root; if setMerkleRoot is unguarded, the proof check is meaningless and any leaf can be forged.
