# Moonhacker vault: unvalidated mToken in executeOperation drains USDC

Moonhacker vault's unauthenticated executeOperation lacked mToken validation, letting attacker pass malicious contract, gain USDC approval, and drain ~$320k.

- Payout: Real-world hack
- Severity: critical
- Program: Moonhacker
- Credited: DeFiHackLabs
- Disclosed: 2024-12-23
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-12/Moonhacker_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20241223-moonhacker
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:flash-loan

**Target:** Moonhacker vault contract (executeOperation) on Optimism interacting with Moonwell mUSDC
**Root cause:** executeOperation was externally callable with no access control and did not validate that the mToken parameter was a legitimate Moonwell market, so an attacker-supplied contract received token approvals.
**Steps:**
1. Flash loan 883,917,967,954 USDC from Aave V3 on Optimism.
2. In callback, loop 4x: call `mUSDC.borrowBalanceCurrent(moonhacker)` and `getAccountSnapshot(moonhacker)` to read borrow balance and mToken balance.
3. Transfer USDC equal to borrowBalance to moonhacker, then call `moonhacker.executeOperation(USDC, borrowBalance, 0, attacker, abi.encode(1, mUSDC, mTokenBalance))` to repay and redeem.
4. Call `moonhacker.executeOperation(USDC, moonhackerUSDCBalance, 0, attacker, abi.encode(0, attacker, 0))` so vault approves attacker, then `USDC.transferFrom(moonhacker, attacker, balance)`.
5. Repay Aave flash loan plus premium and keep profit.
**How found:** Analysis identified that executeOperation lacked access control and never validated the mToken argument against a whitelist of real Moonwell markets, allowing an arbitrary contract to be substituted and receive approvals.
**Exploitation:** Attacker flash-loaned USDC from Aave, repeatedly drove the vault's repay/redeem cycle to inflate its USDC balance, then abused the unauthenticated executeOperation with attacker-controlled params to make the vault approve and transfer its USDC out, repaying the loan and keeping ~$320k.
**Escalation:** Repeated the redeem/returnFunds cycle 4 times to maximize drained balance before repaying the flash loan.
**Insight:** In vault/strategy contracts that wrap lending markets, check whether externally callable callback functions (executeOperation, onFlashLoan, etc.) validate the market/token argument against a whitelist and restrict callers; an unvalidated mToken lets you redirect approvals.
