We do not have a reliable USD price for the recorded assets yet.
0x75a04a1fee9e6f26385ab1287b20ebdcbdabe478Ethereum0xd60eea80c83779a8a5bfcdac1f3323548e6bb62dEthereumAn 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.
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.
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:
0xecc6ec6a9685ec90eb68c40e995f7b34953b258397df4915d5902a312798b1240x78db13b0d7495cae1d45d8d113f83d70b0395c059cf83593d4dd2a9511e16f4bFor 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.
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 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"
}
]
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.