# LegendaryMoneyMonNft: ecrecover address(0) bypass drains MON treasury

LegendaryMoneyMonNft's cliamRewred accepted a zero r/s signature because ecrecover returned address(0), matching the zeroed admin, draining ~85.5K USDT of MON.

- Payout: Real-world hack
- Severity: critical
- Program: LegendaryMoneyMonNft
- Credited: DeFiHackLabs
- Disclosed: 2026-05-28
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-05/LegendaryMoneyMonNft_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260528-legendarymoneymonnft
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:source-review vuln:access-control vuln:auth-bypass vuln:signature-replay

**Target:** BSC NFT claim contract (cliamRewred signature verification)
**Root cause:** recoverSigner returns ecrecover output without rejecting address(0); a malformed (r=0,s=0,v=27) signature yields address(0), and admin had been set to the zero address via changeadmin, so verify() passes.
**Steps:**
1. Fork BSC at block 100937038; confirm NFT.admin() == address(0).
2. Build forged 65-byte sig `abi.encodePacked(bytes32(0), bytes32(0), uint8(27))`.
3. Call `cliamRewred(address(MON), MON.balanceOf(NFT), 0, block.timestamp, "", forgedSig)` as attacker.
4. Approve PancakeV3 SmartRouter and swap stolen MON to USDT via `exactInputSingle` (fee 2500).
**How found:** Recognized that ecrecover returns address(0) on malformed signatures and that the contract never checks for it; combined with on-chain observation that admin had been set to the zero address, making the zero-return match.
**Exploitation:** Attacker EOA (via EIP-7702 SetCode delegation to 0x157ba211...) called cliamRewred with a zero r/s signature; ecrecover returned address(0) equal to admin, verify passed, contract transferred its full MON balance to the attacker, who swapped it to USDT on PancakeSwap V3.
**Insight:** When auditing signature-gated claims, check whether admin/owner was ever set to address(0) (via changeadmin/renounce) and whether recoverSigner rejects address(0) — a zero r/s/v=27 signature then forges any 'admin' approval.
