All incidents

Unlimited-Mint Collateral Used to Over-Mint Debt Token

Share
Sep 20, 2024 22:43 UTCAttackLoss: 98,999,168,398.02 0xd60e...b62dManually checked4 exploit txWindow: 34m 36s
Estimated Impact
98,999,168,398.02 0xd60e...b62d
Label
Attack
Exploit Tx
4
Addresses
2
Attack Window
34m 36s
Sep 20, 2024 22:43 UTC → Sep 20, 2024 23:17 UTC

Exploit Transactions

TX 1Ethereum
0x39328ea4377a8887d3f6ce91b2f4c6b19a851e2fc5163e2f83bbc2fc136d0c71
Sep 20, 2024 22:44 UTCExplorer
TX 2Ethereum
0x358b0f89fdd4c43045c3cbd2b5b0b588238ec320e75d4c383ac7ba26bb726185
Sep 20, 2024 22:43 UTCExplorer
TX 3Ethereum
0xecc6ec6a9685ec90eb68c40e995f7b34953b258397df4915d5902a312798b124
Sep 20, 2024 22:46 UTCExplorer
TX 4Ethereum
0x78db13b0d7495cae1d45d8d113f83d70b0395c059cf83593d4dd2a9511e16f4b
Sep 20, 2024 23:17 UTCExplorer

Victim Addresses

0x75a04a1fee9e6f26385ab1287b20ebdcbdabe478Ethereum
0xd60eea80c83779a8a5bfcdac1f3323548e6bb62dEthereum

Loss Breakdown

98,999,168,398.020xd60e...b62d

Similar Incidents

Root Cause Analysis

Unlimited-Mint Collateral Used to Over-Mint Debt Token

1. Incident Overview TL;DR

An unprivileged EOA on Ethereum mainnet deployed a helper contract that mints an unbounded amount of collateral token 0x6412...7924 to itself and immediately uses it as collateral in a generic debt aggregator proxy 0x75a0...e478. In the same transaction, the aggregator’s borrow path mints 98,999,168,398.02 units of debt token 0xd60e...b62d to the adversary without any economically scarce backing.

Root cause in short: Collateral token 0x6412...7924 exposes a fully permissionless, unbounded mint(address,uint256), and the debt aggregator treats balances of this token as valid collateral when computing credit limits; this composition lets anyone mint arbitrary collateral and over-mint 0xd60e...b62d in a single transaction.

2. Key Background

Collateral token 0x641249db01d5c9a04d1a223765ffd15f95167924 is an ERC20-like contract where mint(address,uint256) is callable by any address and directly increases totalSupply and the recipient balance without caps or access control. Debt token 0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d is an AccessControl-enabled ERC20 whose mint(address,uint256) is restricted to callers with MINTER_ROLE and is used by the protocol to materialize user debt when borrowing against collateral. Aggregator proxy 0x75a04a1fee9e6f26385ab1287b20ebdcbdabe478 is an OpenZeppelin TransparentUpgradeableProxy pointing to implementation 0xa35f69899796ddbc4a8904511d2f1f040b779cb7, which manages per-user collateral balances and debt accounting and holds MINTER_ROLE on 0xd60e...b62d. Helper/oracle contract 0x8568f224429c602e893d51652e38326a5d6183b6 provides getPriceUSD and getCreditLimitUSD helpers that value collateral using a price feed and a configured baseCreditLimitRate, with no logic to discount or block freely mintable tokens. Under normal assumptions, users are expected to deposit economically scarce collateral into the aggregator, which then mints a bounded amount of 0xd60e...b62d debt tokens consistent with that collateral value.

3. Vulnerability Analysis & Root Cause Summary

Category: ATTACK

Summary: The protocol accepts an ERC20 token with a public, unbounded mint function as collateral and computes credit limits directly from its balance and oracle price, allowing anyone to mint arbitrary collateral and over-mint debt token 0xd60e...b62d.

Invariant:

For all user addresses u, the total supply of 0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d minted into user-controlled accounts must be bounded by the value of economically scarce collateral backing their positions, after accounting for protocol parameters and risk discounts.

Breakpoint (where the invariant is violated):

Collateral token 0x6412...7924 implements mint(address,uint256) as a public function callable by any address without access control or caps, and the aggregator implementation 0xa35f...9cb7 together with helper 0x8568...83b6 treats balances of 0x6412...7924 as fully valid collateral when computing credit limits, so an attacker contract that calls 0x6412...7924.mint(max_uint256) and then enters the borrow path can cause 0xd60e...b62d.mint() to create arbitrary debt tokens.

4. Detailed Root Cause Analysis

Decompiled collateral contract 0x641249db01d5c9a04d1a223765ffd15f95167924 exposes mint(address,uint256) publicly with no owner, role, or cap checks. Any caller can invoke mint(to, amount) to increase totalSupply and the recipient’s balance by amount, subject only to a zero-address guard. The debt aggregator system, fronted by proxy 0x75a0...e478 and implemented at 0xa35f...9cb7, is designed to accept ERC20 collateral tokens and compute per-user credit limits based on balances and oracle prices, using helper 0x8568...83b6. In the seed transaction, EOA 0xa3a6...01a1d deploys helper contract 0xed4b...499c, which in its constructor (1) approves proxy 0x75a0...e478 to spend its 0x6412...7924 balance, (2) mints max_uint256 0x6412...7924 tokens to itself using the public mint function, (3) calls the aggregator proxy with selector 0xbcc46e83 to deposit the entire balance as collateral, and (4) invokes the borrow path that causes implementation 0xa35f...9cb7 to call 0xd60e...b62d.mint() and mint 98,999,168,398.02 units of 0xd60e...b62d first to 0xed4...499c and then to the EOA. Because the aggregator does not distinguish freely mintable collateral from scarce assets, it treats the max_uint256 balance as genuine value, breaks the invariant that debt must be collateral-backed, and allows an unprivileged user to materialize essentially unbacked debt tokens.

Key conditions required for the ACT opportunity:

  • Collateral token with public, unbounded mint(address,uint256) (0x6412...7924) is added to the aggregator as an accepted collateral asset.
  • Aggregator implementation 0xa35f...9cb7 and helper 0x8568...83b6 compute credit limits from raw balances and oracle prices without guarding against freely mintable collateral.
  • An unprivileged EOA can deploy a helper contract that mints a very large 0x6412...7924 balance, approves the aggregator, deposits the balance as collateral, and calls the borrow function within a single transaction.
  • Debt token 0xd60e...b62d recognizes the aggregator implementation as a valid MINTER_ROLE holder and does not independently check the quality of collateral backing the minted debt.

Key Code and Trace Evidence

Collateral token 0x641249db01d5c9a04d1a223765ffd15f95167924 exposes a public, unbounded mint(address,uint256):

    /// @custom:selector    0x40c10f19
    /// @custom:signature   mint(address arg0, uint256 arg1) public payable returns (bool)
    /// @param              arg0 ["address", "uint160", "bytes20", "int160"]
    /// @param              arg1 ["uint256", "bytes32", "int256"]
    function mint(address arg0, uint256 arg1) public payable returns (bool) {
        require(arg0 == (address(arg0)));
        require(address(arg0), "ERC20: mint to the zero address");
        require(!(totalSupply > (arg1 + totalSupply)), "ERC20: mint to the zero address");
        var_a = 0x4e487b7100000000000000000000000000000000000000000000000000000000;
        var_b = 0x11;
        totalSupply = arg1 + totalSupply;
        address var_a = address(arg0);
        uint256 var_c = 0;
        storage_map_a[var_a] = arg1 + storage_map_a[var_a];
        uint256 var_d = arg1;
        emit Transfer(0, address(arg0), arg1);
        var_d = 0x01;
        return 0x01;
        var_d = 0x08c379a000000000000000000000000000000000000000000000000000000000;
        var_e = 0x20;
        var_f = 0x1f;
        var_g = 0x45524332303a206d696e7420746f20746865207a65726f206164647265737300;
    }

Seed transaction trace excerpt for 0x3932...0c71, showing helper approve/mint collateral, aggregator addCollateral/borrow, and debt token mint:

[
  {
    "from": "0xed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "to": "0x641249db01d5c9a04d1a223765ffd15f95167924",
    "input": "0x095ea7b300000000000000000000000075a04a1fee9e6f26385ab1287b20ebdcbdabe478ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
    "type": "CALL",
    "value": "0x0",
    "gasUsed": "0x6035"
  },
  {
    "from": "0xed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "to": "0x641249db01d5c9a04d1a223765ffd15f95167924",
    "input": "0x40c10f19000000000000000000000000ed4b3d468ded53a322a8b8280b6f35aae8bc499c00000000000000000000000000000000ffffffffffffffffffffffffffffffff",
    "type": "CALL",
    "value": "0x0",
    "gasUsed": "0x739f"
  },
  {
    "from": "0xed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "to": "0x75a04a1fee9e6f26385ab1287b20ebdcbdabe478",
    "input": "0xbcc46e8300000000000000000000000000000000ffffffffffffffffffffffffffffffff",
    "type": "CALL",
    "value": "0x0",
    "gasUsed": "0x1d40e"
  },
  {
    "from": "0xed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "to": "0x75a04a1fee9e6f26385ab1287b20ebdcbdabe478",
    "input": "0xc5ebeaec0000000000000000000000000000000000000001431d5dcdd3ee7920d4380000",
    "type": "CALL",
    "value": "0x0",
    "gasUsed": "0x2460d"
  },
  {
    "from": "0xed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "to": "0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d",
    "input": "0x70a08231000000000000000000000000ed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "type": "STATICCALL",
    "value": null,
    "gasUsed": "0x247"
  },
  {
    "from": "0xed4b3d468ded53a322a8b8280b6f35aae8bc499c",
    "to": "0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d",
    "input": "0xa9059cbb000000000000000000000000a3a64255484ad65158af0f9d96b5577f79901a1d00000000000000000000000000000000000000013fe2315891cfedad4cfa0000",
    "type": "CALL",
    "value": "0x0",
    "gasUsed": "0x627f"
  }
]

5. Adversary Flow Analysis

6. Impact & Losses

  • Token 0xd60e...b62d: 98999168398.02 minted to adversary-related accounts

The protocol’s debt token 0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d experienced an extreme supply increase, with 98,999,168,398.02 new units minted directly to an adversary-controlled address in a single block without economically scarce collateral. Even if secondary-market valuations fluctuate, this unbacked issuance breaks the intended collateralization invariant, undermines the credibility of the debt token, and can render existing positions effectively worthless or unmanageable.

7. References

  • [1] Seed transaction metadata and receipt for 0x3932...0c71 — artifacts/root_cause/data_collector/iter_1/tx/1/0x39328ea4377a8887d3f6ce91b2f4c6b19a851e2fc5163e2f83bbc2fc136d0c71/tx_metadata_and_receipt_simplified.json
  • [2] Seed transaction debug trace — artifacts/root_cause/data_collector/iter_1/tx/1/0x39328ea4377a8887d3f6ce91b2f4c6b19a851e2fc5163e2f83bbc2fc136d0c71/tx_trace_debug_callTracer.json
  • [3] Decompiled collateral token 0x6412...7924 — artifacts/root_cause/data_collector/iter_1/contract/1/0x641249db01d5c9a04d1a223765ffd15f95167924/decompile/0x641249db01d5c9a04d1a223765ffd15f95167924-decompiled.sol
  • [4] Decompiled debt token 0xd60e...b62d — artifacts/root_cause/data_collector/iter_2/contract/1/0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d/decompile/0xd60eea80c83779a8a5bfcdac1f3323548e6bb62d-decompiled.sol
  • [5] Decompiled aggregator implementation 0xa35f...9cb7 — artifacts/root_cause/data_collector/iter_2/contract/1/0xa35f69899796ddbc4a8904511d2f1f040b779cb7/decompile/0xa35f69899796ddbc4a8904511d2f1f040b779cb7-decompiled.sol
  • [6] Decompiled helper/oracle 0x8568...83b6 — artifacts/root_cause/data_collector/iter_2/contract/1/0x8568f224429c602e893d51652e38326a5d6183b6/decompile/0x8568f224429c602e893d51652e38326a5d6183b6-decompiled.sol
  • [7] Adversary address tx history around seed block — artifacts/root_cause/data_collector/iter_1/address/1/0xa3a64255484ad65158af0f9d96b5577f79901a1d/normal_txlist_around_seed_from_blocks.json
  • [8] Downstream debt-token transfer 0x78db...6f4b — artifacts/root_cause/data_collector/iter_2/tx/1/0x78db13b0d7495cae1d45d8d113f83d70b0395c059cf83593d4dd2a9511e16f4b/tx_metadata_and_receipt_simplified.json