# ChaingeFinance: arbitrary call in swap drains token allowances

ChaingeFinance MinterProxyV2.swap allowed arbitrary external calls, letting attackers use victim allowances to transferFrom tokens and steal ~$560K.

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

**Target:** MinterProxyV2 smart contract on BSC
**Root cause:** The swap function accepts arbitrary callData and target token address, then executes an external call without validating that the call is legitimate or that the caller is authorized, allowing arbitrary transferFrom using victim allowances.
**Steps:**
1. Identify victim address with token allowances to MinterProxyV2.
2. For each token, check victim's balance and allowance to MinterProxyV2.
3. Craft callData as `transferFrom(victim, attacker, amount)`.
4. Call `minterproxy.swap(address(this), 1, targetToken, address(this), address(this), 1, transferFromData, bytes(hex"00"))`.
5. Repeat for multiple tokens to drain allowances.
**How found:** Likely identified that swap's callData parameter is user-controlled and executed without validation, and that many users had granted allowances to the proxy.
**Exploitation:** Attacker called swap with a malicious callData that invoked transferFrom on the target token, using the victim's existing allowance to MinterProxyV2 to transfer tokens to the attacker's contract. Repeated for 12 tokens, netting ~$560K.
**Insight:** In DeFi protocols, any function that takes arbitrary calldata and executes it on behalf of the contract can be abused to spend user allowances if the contract holds approvals. Check for such 'proxy' patterns and test with transferFrom.
