All incidents

bZx iYFI Donation Inflation

Share
Dec 02, 2023 02:11 UTCAttackLoss: 38.09 WETH, 0.23 WBTC +11 morePending manual check5 exploit txWindow: 18m 36s
Estimated Impact
38.09 WETH, 0.23 WBTC +11 more
Label
Attack
Exploit Tx
5
Addresses
4
Attack Window
18m 36s
Dec 02, 2023 02:11 UTC → Dec 02, 2023 02:30 UTC

Exploit Transactions

TX 1Ethereum
0x9f8a6ab13a0148d8ad640510692312b9d3d8ac6e0a4165f04ae55dffa18d28a5
Dec 02, 2023 02:11 UTCExplorer
TX 2Ethereum
0xf182c20eddb4730c019ddc49cb96fb15aec7a5b1992839efd8046b5b8aba8e1c
Dec 02, 2023 02:14 UTCExplorer
TX 3Ethereum
0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4
Dec 02, 2023 02:18 UTCExplorer
TX 4Ethereum
0x0fc5c0d41e5506fdb9434fab4815a4ff671afc834e47a533b3bed7182ece73b0
Dec 02, 2023 02:26 UTCExplorer
TX 5Ethereum
0xb072f2e88058c147d8ff643694b43a42e36525b7173ce1daf76e6c06170b0e77
Dec 02, 2023 02:30 UTCExplorer

Victim Addresses

0x7F3Fe9D492A9a60aEBb06d82cBa23c6F32CAd10bEthereum
0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7fEthereum
0xB983E01458529665007fF7E0CDdeCDB74B967Eb6Ethereum
0x2ffa85f655752fB2aCB210287c60b9ef335f5b6EEthereum

Loss Breakdown

38.09WETH
0.226514WBTC
1.2AAVE
115.69APE
0.098157COMP
39,812.62DAI
523.91LINK
1,987.65LRC
0.004481MKR
261,367.66OOKI
613.37UNI
42,329.52USDC
27,251.35USDT

Similar Incidents

Root Cause Analysis

bZx iYFI Donation Inflation

1. Incident Overview TL;DR

On Ethereum mainnet, the attacker used an empty bZx iYFI market to mint the entire 5-unit iYFI supply with only 5 wei of YFI, then reused those same 5 shares as inflated collateral to borrow assets from bZx loan pools. The inflation came from directly donating flash-borrowed YFI to the iYFI loan-token contract, which changed the share price without minting more iYFI. In the minimal profitable sequence, the attacker progressed from 0.350001808365330129 ETH before nonce 0 to 42.085385398837487612 ETH after transaction 0x0fc5c0d41e5506fdb9434fab4815a4ff671afc834e47a533b3bed7182ece73b0, a net gain of 41.735383590472157483 ETH after setup costs and gas. A later related drain transaction, 0xb072f2e88058c147d8ff643694b43a42e36525b7173ce1daf76e6c06170b0e77, raised cumulative observed profit to 99.021695943580894 ETH.

The root cause is a code-level accounting flaw in bZx LoanTokenLogicStandard: tokenPrice() trusts _totalAssetSupply(), and _totalAssetSupply() trusts the raw YFI balance of the iYFI contract. That means unsolicited YFI transfers into the loan-token contract immediately increase the collateral price of existing iYFI shares even though no new shares were minted.

2. Key Background

iYFI is the bZx loan-token market for YFI collateral. Its share price is derived from the market asset supply divided by the outstanding iYFI supply, so pricing is safe only if the asset-supply term reflects assets that actually back minted shares.

In the collected iYFI implementation, asset supply is computed from the loan-token contract's raw YFI balance plus borrowed assets. Because direct ERC-20 transfers can change that raw balance without going through mint logic, the share price is donation-sensitive.

The exploit depended on an empty market. Before attacker nonce 0, the iYFI market had zero total supply and zero YFI backing. In attacker nonce 2, transaction 0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4, the attacker helper swapped public-market WETH for 5 wei YFI and minted exactly 5 iYFI, becoming the sole iYFI holder.

The attacker also deployed its own helper and guard contracts first. Those contracts did not provide privileged access; they were standard attacker-owned infrastructure deployed under normal CREATE semantics, which keeps the opportunity in ACT scope.

3. Vulnerability Analysis & Root Cause Summary

This incident is an ATTACK-class ACT exploit, not an MEV-only unwind and not an access-control issue. The verified victim code shows that iYFI pricing treated unsolicited YFI donations as legitimate collateral backing. Once the attacker owned the entire 5-unit iYFI supply, any YFI donated to the iYFI contract increased the value of those same 5 shares. The attacker used a flash swap to source a large YFI amount, transferred it directly into iYFI, and then borrowed WETH and WBTC against the inflated share price. bZx margin checks accepted the donated value because the borrow path relied on the manipulated iYFI tokenPrice(). After each borrow, the attacker withdrew the same 5 iYFI collateral back out, proving that the protocol treated the same collateral as both fully pledged and immediately withdrawable. The flaw is therefore the donation-sensitive accounting in LoanTokenLogicStandard, with flash liquidity serving only as the funding mechanism.

4. Detailed Root Cause Analysis

The key pricing path in the verified iYFI loan-token implementation is below. This is the decisive code-level breakpoint because _totalAssetSupply() reads the contract's raw YFI balance through _underlyingBalance(), and tokenPrice() feeds that result directly into share valuation:

function tokenPrice() public view returns (uint256) {
    uint256 interestUnPaid;
    if (lastSettleTime_ != uint88(block.timestamp)) {
        (,interestUnPaid) = _getAllInterest();
    }

    return _tokenPrice(_totalAssetSupply(interestUnPaid));
}

function _underlyingBalance() internal view returns (uint256) {
    return IERC20(loanTokenAddress).balanceOf(address(this));
}

function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {
    uint256 totalTokenSupply = totalSupply_;
    return totalTokenSupply != 0
        ? assetSupply.mul(WEI_PRECISION).div(totalTokenSupply)
        : initialPrice;
}

function _totalAssetSupply(uint256 interestUnPaid) internal view returns (uint256) {
    if (totalSupply_ != 0) {
        uint256 assetsBalance = _flTotalAssetSupply;
        if (assetsBalance == 0) {
            assetsBalance = _underlyingBalance().add(totalAssetBorrow());
        }
        return assetsBalance.add(interestUnPaid);
    }
}

The ACT pre-state was Ethereum mainnet immediately before attacker nonce 0 at block 18,695,653. At that point the attacker had not yet deployed the helper or guard, the iYFI market was empty, and no privileged information or privileged addresses were required to proceed.

The bootstrap transaction proves the empty-market setup. The collected balance diff for 0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4 shows YFI increasing by 5 wei at iYFI and iYFI increasing by 5 units at the attacker helper. That establishes that the attacker owned 100% of the iYFI supply with only dust backing.

The minimal exploit trace then shows the exact exploit sequence:

LoanTokenLogicStandard::burn(0x03b7..., 5)
LoanTokenLogicStandard::mint(0x03b7..., 5)
YFI::transfer(LoanToken: [0x7F3Fe9D492A9a60aEBb06d82cBa23c6F32CAd10b], 19363816309062560431)
0xB983E01458529665007fF7E0CDdeCDB74B967Eb6::borrow(..., 38089742649328258427, ..., 5, LoanToken: [0x7F3F...], 0x03b7..., 0x03b7..., 0x)
0x91fcdb277e84642Ef29db708Ff35aA48bA20F04d::withdrawCollateral(..., 0x03b7..., 5)
LoanTokenLogicStandard::borrow(..., 22651422, ..., 5, LoanToken: [0x7F3F...], 0x03b7..., 0x03b7..., 0x)
0x91fcdb277e84642Ef29db708Ff35aA48bA20F04d::withdrawCollateral(..., 0x03b7..., 5)
LoanTokenLogicStandard::burn(0x03b7..., 5)
LoanTokenLogicStandard::mint(0x03b7..., 5)

This trace demonstrates all critical state transitions. The attacker first restored the tiny 5-share state, then donated 19.363816309062560431 YFI directly into iYFI, then opened WETH and WBTC borrows using only 5 iYFI as collateral, and then withdrew the same 5 iYFI back out after each borrow. That behavior is impossible unless bZx is valuing the 5 iYFI shares from the donated underlying balance rather than from minted-share accounting.

The attacker EOA and helper balance diffs quantify the realization. The attacker EOA began with 0.350001808365330129 ETH before nonce 0, fell to 0.203289208365230129 ETH after the setup transactions, and ended the minimal exploit transaction with 42.085385398837487612 ETH. The protocol therefore transferred 41.735383590472157483 ETH of net value to an unprivileged adversary in the minimal ACT sequence.

The exploit required only three objective conditions: an otherwise empty iYFI market, the ability to donate YFI directly into the iYFI contract without minting more shares, and continued use of the resulting tokenPrice() in bZx borrow and collateral-withdraw validation. Those conditions are exactly the ACT exploit conditions captured in the validated root cause. The violated security principles are also concrete: collateral pricing must not trust raw ERC-20 balances when unsolicited transfers are possible, share-accounting invariants must distinguish deposits from donations, and collateral withdrawal logic must not rely on a borrower-manipulable collateral price.

5. Adversary Flow Analysis

The attacker cluster consisted of:

  • 0x5a7c7eb8d13a53d42a15d2b1d1b694ccc5141ea5: attacker EOA, sender of nonce 0 through nonce 4 and final profit recipient.
  • 0x03b7bb750a974e0bd34795013f66b669f4110e54: attacker helper contract created by that EOA in 0xf182c20eddb4730c019ddc49cb96fb15aec7a5b1992839efd8046b5b8aba8e1c.
  • 0x65d877b569cc84970baf52c38178c1adf27167c3: attacker guard contract created in 0x9f8a6ab13a0148d8ad640510692312b9d3d8ac6e0a4165f04ae55dffa18d28a5 and wired into the helper constructor.

The end-to-end attacker flow was:

  1. 0x9f8a6ab13a0148d8ad640510692312b9d3d8ac6e0a4165f04ae55dffa18d28a5 at block 18,695,654: The attacker deployed the guard contract. This was a normal, permissionless deployment.
  2. 0xf182c20eddb4730c019ddc49cb96fb15aec7a5b1992839efd8046b5b8aba8e1c at block 18,695,668: The attacker deployed the helper contract and hard-wired public addresses for iYFI, YFI, WETH, routers, pools, and bZx.
  3. 0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4 at block 18,695,689: The helper wrapped 100000 wei into WETH, swapped 21 wei WETH for 5 wei YFI, and minted the entire 5-unit iYFI supply.
  4. 0x0fc5c0d41e5506fdb9434fab4815a4ff671afc834e47a533b3bed7182ece73b0 at block 18,695,729: The helper flash-swapped YFI from the public Sushi pair, donated that YFI into iYFI, borrowed 38.089742649328258427 WETH and 0.22651422 WBTC against the inflated price, withdrew the same 5 iYFI collateral back out, repaid the flash swap, and sent the residual profit to the attacker EOA.
  5. 0xb072f2e88058c147d8ff643694b43a42e36525b7173ce1daf76e6c06170b0e77 at block 18,695,746: The attacker repeated the same primitive against additional bZx pools holding AAVE, APE, COMP, DAI, LINK, LRC, MKR, OOKI, UNI, USDC, and USDT.

The helper and guard contracts do not negate ACT status. They were attacker-deployed infrastructure created during the observed sequence, and every required address except those attacker-owned deployments was a public protocol component available to any unprivileged searcher.

6. Impact & Losses

The minimal profitable exploit drained the WETH and WBTC pools immediately:

  • WETH: 38089742649328258427 raw units, or 38.089742649328258427 WETH.
  • WBTC: 22651422 raw units, or 0.22651422 WBTC.

The repeated transaction then drained at least the following additional assets from other bZx loan pools:

  • AAVE: 1203854018221517355
  • APE: 115693075453404239155
  • COMP: 98157285309061937
  • DAI: 39812621697493752003219
  • LINK: 523914254804415005610
  • LRC: 1987645891232163697748
  • MKR: 4481000000000000
  • OOKI: 261367663862900000000000
  • UNI: 613367858249823222724
  • USDC: 42329522649
  • USDT: 27251348437

At a protocol level, the impact was broader than the token list. bZx accepted the same 5 iYFI units as collateral multiple times even after the attacker had already withdrawn those units back out, so the protocol's collateralization logic no longer enforced the intended backing invariant.

7. References

  • Attacker pre-seed sequence for 0x5a7c7eb8d13a53d42a15d2b1d1b694ccc5141ea5: /workspace/session/artifacts/collector/iter_1/address/1/0x5a7c7eb8d13a53d42a15d2b1d1b694ccc5141ea5/pre_seed_sequence.json
  • Helper creation provenance for 0x03b7bb750a974e0bd34795013f66b669f4110e54: /workspace/session/artifacts/collector/iter_1/contract/1/0x03b7bb750a974e0bd34795013f66b669f4110e54/creation_provenance.json
  • Bootstrap trace for 0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4: /workspace/session/artifacts/collector/iter_1/tx/1/0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4/trace.cast.log
  • Bootstrap balance diff for 0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4: /workspace/session/artifacts/collector/iter_1/tx/1/0xeff478f07c4e1d68f5997510b5a0978afd7f2716dbd65f759180496d955111c4/balance_diff.json
  • Minimal exploit trace for 0x0fc5c0d41e5506fdb9434fab4815a4ff671afc834e47a533b3bed7182ece73b0: /workspace/session/artifacts/collector/seed/1/0x0fc5c0d41e5506fdb9434fab4815a4ff671afc834e47a533b3bed7182ece73b0/trace.cast.log
  • Repeated exploit trace for 0xb072f2e88058c147d8ff643694b43a42e36525b7173ce1daf76e6c06170b0e77: /workspace/session/artifacts/collector/seed/1/0xb072f2e88058c147d8ff643694b43a42e36525b7173ce1daf76e6c06170b0e77/trace.cast.log
  • Verified iYFI loan-token implementation (LoanTokenLogicStandard): /workspace/session/artifacts/collector/seed/1/0xfb772316a54dcd439964b561fc2c173697aeeb5b/src/Contract.sol