Calculated from recorded token losses using historical USD prices at the incident time.
0xa5d09bd730ac728c36757c64eaa64d960689a38bd1ae0e00c317b2f690548e200x7193794ec82f527efb618ac50c078d348ecba4b6Ethereum0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcbEthereumOn Ethereum mainnet block 24715726, transaction 0xa5d09bd730ac728c36757c64eaa64d960689a38bd1ae0e00c317b2f690548e20 used only permissionless calls to Morpho, MetaMorpho, and Curve to extract immediate profit. The attacker flash-loaned 86,939,029.794907 USDC from Morpho, swapped 10,000 USDC on Curve into 19,366.776625939460173334 SimpleToken, deposited 86,910,029.794907 USDC into the MetaMorpho vault 0x7193794ec82f527efb618ac50c078d348ecba4b6, supplied 19,000 USDC into the target Morpho market on behalf of that vault, borrowed 19,000 USDC against the freshly bought SimpleToken collateral, redeemed the newly minted vault shares for 86,925,812.568533 USDC, repaid the flash loan, and transferred 5,782.773626 USDC to EOA 0x37d85b845e947b7e51aba5cb041d61f6ef1d2e4b.
The root cause is the combination of two independently exploitable conditions. First, MetaMorpho counts Morpho positions owned by the vault as redeemable vault assets even when those positions were increased by a third party through Morpho.supply(... onBehalf = vault) and no vault shares were minted to that donor. Second, the SimpleToken Morpho market accepted an oracle price that allowed collateral acquired for 10,000 USDC on Curve to support a USDC borrow at LLTV. Together, those conditions made the incident an ACT opportunity rather than a privileged exploit.
19,00086%Morpho Blue exposes permissionless lending primitives. In particular, any caller can use flashLoan, can supply assets to a market on behalf of any address, can post collateral for itself, and can borrow when the oracle and LLTV checks pass.
MetaMorpho is an ERC4626-style vault over Morpho positions. Its share pricing depends on lastTotalAssets, and its total asset accounting is derived from the Morpho positions held by the vault address across the withdraw queue rather than from vault-share mint history. That design matters because it makes third-party changes to vault-owned Morpho positions visible to future redeem() calculations.
The target collateral market used loan token USDC 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48, collateral token SimpleToken 0x4956b52ae2ff65d74ca2d61207523288e4528f96, oracle 0x19018450A02bC5c1994eaD517498311f64B2626a, IRM 0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC, and LLTV 860000000000000000. The same transaction could buy SimpleToken from Curve pool 0x8e001d4bac0eae1eea348dfc22f9b8bda67dd211, immediately post it as collateral, and then borrow USDC against the oracle valuation.
This incident is an ATTACK-category ACT exploit, not a pure MEV opportunity. The first broken invariant is vault-share fairness: a MetaMorpho shareholder must not be able to redeem capital that another party injected into the vault's Morpho positions unless the injector receives corresponding vault shares. The second broken invariant is collateral valuation safety: a Morpho borrow must not accept a collateral price materially above the same transaction's executable market price when that gap can create immediate undercollateralized debt.
The verified MetaMorpho code implements the accounting breakpoint. deposit() and redeem() both convert against lastTotalAssets, while _accruedFeeAndAssets() recomputes vault assets by summing MORPHO.expectedSupplyAssets(_marketParams(withdrawQueue[i]), address(this)) for the vault address. Because Morpho supply() lets the caller choose any onBehalf owner, an attacker can increase the vault's Morpho supply position without receiving MetaMorpho shares. That lets a fresh shareholder redeem a larger share of assets than it economically contributed.
The verified Morpho interface and the trace implement the second breakpoint. The attacker buys SimpleToken on Curve for 10,000 USDC, posts all 19,366.776625939460173334 tokens as collateral, and immediately borrows 19,000 USDC. The trace shows that Morpho::borrow consulted the SimpleToken oracle before approving that borrow. The fact that the borrow succeeds after the attacker just established a much lower executable Curve price proves that the market accepted an overvalued collateral price relative to same-transaction execution.
The victim-side MetaMorpho code makes the accounting issue explicit:
function deposit(uint256 assets, address receiver) public override returns (uint256 shares) {
_accrueInterest();
shares = _convertToSharesWithTotals(assets, totalSupply(), lastTotalAssets, Math.Rounding.Floor);
_deposit(_msgSender(), receiver, assets, shares);
}
function redeem(uint256 shares, address receiver, address owner) public override returns (uint256 assets) {
_accrueInterest();
assets = _convertToAssetsWithTotals(shares, totalSupply(), lastTotalAssets, Math.Rounding.Floor);
_withdraw(_msgSender(), receiver, owner, assets, shares);
}
function _accruedFeeAndAssets()
internal
view
returns (uint256 feeShares, uint256 newTotalAssets, uint256 newLostAssets)
{
uint256 realTotalAssets;
for (uint256 i; i < withdrawQueue.length; ++i) {
realTotalAssets += MORPHO.expectedSupplyAssets(_marketParams(withdrawQueue[i]), address(this));
}
}
The Morpho permissioning that enables the donation is also explicit:
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
In the seed trace, the attacker executes the critical sequence in one transaction:
Morpho::supplyCollateral(... assets: 19366776625939460173334, onBehalf: attacker)
Morpho::supply(... assets: 19000000000, onBehalf: 0x7193794ec82f527Efb618Ac50C078D348eCBA4b6)
Morpho::borrow(... assets: 19000000000, onBehalf: attacker, receiver: attacker)
0x7193794ec82f527Efb618Ac50C078D348eCBA4b6::redeem(... 85379210839054633386625442, attacker, attacker)
emit Transfer(from: 0x7193794..., to: attacker, value: 86925812568533)
emit Transfer(from: attacker, to: 0x37D85b..., value: 5782773626)
That evidence yields a deterministic accounting decomposition:
86,910,029.794907 USDC into MetaMorpho and receives 85,379,210,839,054,633,386,625,442 vault shares.19,000 USDC into the SimpleToken Morpho market on behalf of the vault, increasing the vault's Morpho-owned supply position without minting new MetaMorpho shares.redeem() re-prices the just-minted shares against the updated vault asset base, the attacker receives 86,925,812.568533 USDC back.15,782.773626 USDC (86,925,812.568533 - 86,910,029.794907).The same trace proves the collateral valuation mismatch. Before the borrow, the attacker swaps 10,000 USDC for 19,366.776625939460173334 SimpleToken on Curve. Immediately after posting those tokens as collateral, Morpho::borrow consults 0x19018450A02bC5c1994eaD517498311f64B2626a::price() and permits a 19,000 USDC borrow. Because the attacker established the executable market acquisition price in the same transaction, the successful borrow demonstrates that the oracle value materially exceeded the executable market value. The exploit only becomes immediately profitable because the borrowed 19,000 USDC also funds the vault-side donation and can then be recovered via the inflated MetaMorpho redemption.
The adversary cluster consists of EOA 0x37d85b845e947b7e51aba5cb041d61f6ef1d2e4b and contract 0xdc5f62652ebcbc1c2049fbd891fe6427ae498f98. The EOA submits the transaction and receives the final USDC transfer; the contract performs the full exploit path.
The lifecycle is:
Morpho::flashLoan(USDC, 86939029794907, ...) gives the contract temporary USDC liquidity.10,000 USDC on Curve for 19,366.776625939460173334 SimpleToken and approves Morpho.86,910,029.794907 USDC into MetaMorpho, minting vault shares at the pre-donation asset price.19,000 USDC to the same Morpho market on behalf of the MetaMorpho vault, seeding borrowable liquidity while also increasing the vault's redeemable asset base.19,000 USDC from the market against the overvalued SimpleToken collateral.86,925,812.568533 USDC, which includes the value attributed to the on-behalf donation.5,782.773626 USDC is transferred to the EOA.This is end-to-end ACT behavior. Every step uses public contracts, public pricing state, and permissionless entrypoints. No privileged signer, attacker-specific bytecode dependency, or private protocol role is required.
The measured immediate attacker profit is 5,782.773626 USDC, encoded on-chain as 5782773626. The balance diff shows the attacker EOA moved from 0 to 5782773626 USDC and paid 237036670838400 wei in gas. Morpho's USDC balance decreased by 15,782.773626 USDC over the transaction, matching the vault round-trip extraction recorded in the trace.
The economic damage is larger than the immediate profit alone. The exploit leaves behind a 19,000 USDC borrow position backed by SimpleToken collateral that the attacker acquired for only 10,000 USDC at the same transaction's executable Curve price. The transaction therefore realizes immediate profit while also leaving residual credit risk in the affected Morpho market.
0xa5d09bd730ac728c36757c64eaa64d960689a38bd1ae0e00c317b2f690548e200x37d85b845e947b7e51aba5cb041d61f6ef1d2e4b0xdc5f62652ebcbc1c2049fbd891fe6427ae498f980x7193794ec82f527efb618ac50c078d348ecba4b60xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb0x4956b52ae2ff65d74ca2d61207523288e4528f960x8e001d4bac0eae1eea348dfc22f9b8bda67dd211/workspace/session/artifacts/collector/seed/1/0x7193794ec82f527efb618ac50c078d348ecba4b6/src/MetaMorphoV1_1.sol/workspace/session/artifacts/collector/seed/1/0x7193794ec82f527efb618ac50c078d348ecba4b6/lib/morpho-blue/src/interfaces/IMorpho.sol/workspace/session/artifacts/collector/seed/1/0xa5d09bd730ac728c36757c64eaa64d960689a38bd1ae0e00c317b2f690548e20/trace.cast.log/workspace/session/artifacts/collector/seed/1/0xa5d09bd730ac728c36757c64eaa64d960689a38bd1ae0e00c317b2f690548e20/balance_diff.json