Calculated from recorded token losses using historical USD prices at the incident time.
0x23479229e52ab6aad312d0b03df9f33b46753b5eBase0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcbBaseOn Base block 43760911, an unprivileged attacker used Morpho flash liquidity and public USR/USDC liquidity to exploit MetaMorpho's vault accounting. The attacker deposited USDC into MetaMorpho to mint shares, bought discounted USR from the public stable AMM, supplied that USR as Morpho collateral, then permissionlessly supplied USDC to the USR market on behalf of MetaMorpho before borrowing the same USDC back and redeeming the same MetaMorpho shares. The vault treated the injected supply position as valid managed assets immediately, so the same share balance redeemed for more USDC than had been deposited.
The root cause is that MetaMorpho trusts MORPHO.expectedSupplyAssets(...) across its tracked withdrawQueue markets when valuing shares, while Morpho allows any caller to create supply positions on behalf of any address. In the affected USR market, the attacker could pair that permissionless supply-on-behalf path with oracle-priced USR collateral that was materially cheaper on the public AMM, turning toxic third-party market exposure into inflated MetaMorpho share value and extractable USDC.
MetaMorpho V1_1 is an ERC4626-style vault over Morpho Blue markets. Deposits and redemptions are priced from the vault's notion of total assets, not just idle token balances. The critical detail is that MetaMorpho tracks a withdrawQueue of Morpho markets and values each tracked market through Morpho's expectedSupplyAssets.
Morpho Blue, separately, allows permissionless supply on behalf of arbitrary addresses:
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
That means anyone can create a supply position owned by MetaMorpho inside a tracked market, even if MetaMorpho never initiated that position itself.
The targeted Morpho market used USDC as the loan asset, USR as collateral, and MorphoChainlinkOracleV2 for pricing. The oracle returned roughly 1 USDC per USR:
function price() external view returns (uint256) {
return SCALE_FACTOR.mulDiv(
BASE_VAULT.getAssets(BASE_VAULT_CONVERSION_SAMPLE) * BASE_FEED_1.getPrice() * BASE_FEED_2.getPrice(),
QUOTE_VAULT.getAssets(QUOTE_VAULT_CONVERSION_SAMPLE) * QUOTE_FEED_1.getPrice() * QUOTE_FEED_2.getPrice()
);
}
The collected live observations show price() = 1000099949989001900849970, while the public USR/USDC stable pool was simultaneously offering materially cheaper USR.
The issue is an accounting attack, not an access-control failure inside MetaMorpho's own entrypoints. MetaMorpho assumes that any supply position owned by the vault inside a tracked Morpho market is economically valid vault inventory. That assumption breaks because Morpho's supply(..., onBehalf, ...) path is permissionless and does not require MetaMorpho consent.
MetaMorpho's pricing path makes the problem exploitable. deposit() and redeem() both call _accrueInterest(), and _accruedFeeAndAssets() then recomputes assets by summing MORPHO.expectedSupplyAssets for every tracked market. If the attacker injects a MetaMorpho-owned supply position into a tracked market immediately after minting shares, the same shares are later redeemed against a larger lastTotalAssets value. In this case the attacker chose the USR market because oracle-priced collateral let them borrow back the supplied USDC while externalizing the economic weakness through discounted USR acquired on a public AMM. The violated invariant is straightforward: the same MetaMorpho shares must not redeem for more USDC than was deposited when the vault has not earned real profit.
The relevant MetaMorpho pricing logic is visible in the verified source:
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);
}
The asset computation that drives both paths is:
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));
}
...
}
Because the affected USR market was already present in MetaMorpho's withdrawQueue, any extra Morpho supply shares owned by MetaMorpho in that market were counted immediately. The attack sequence captured in the seed trace is:
MetaMorpho::deposit(103755853906929, attacker)
Morpho::supplyCollateral(USR market, 14329023497540246028545, attacker, "")
Morpho::supply(USR market, 13111056490, 0, MetaMorpho, "")
Morpho::borrow(USR market, 13111056490, 0, attacker, attacker)
MetaMorpho::redeem(97647114676961779085817360, attacker, attacker)
That call flow proves the exploit uses only public entrypoints. The attacker first minted MetaMorpho shares with 103755853906929 USDC. The attacker then acquired 14329023497540246028545 USR from the public USR/USDC pool, posted it as collateral, and supplied 13111056490 USDC to the same Morpho market on behalf of MetaMorpho. Since Morpho accepts arbitrary onBehalf targets, MetaMorpho now owned new supply shares in that tracked market even though the position was attacker-created.
At the next accounting refresh, MetaMorpho counted those injected shares via expectedSupplyAssets. The attacker simultaneously borrowed the same USDC back against the oracle-priced USR collateral, so the attacker retained the borrowed loan asset while MetaMorpho's accounting recognized the newly injected supply as if it were curator-approved productive assets. The same MetaMorpho share balance then redeemed for 103765377154926 USDC, exceeding the original deposit by 9523247997 USDC in the validator PoC and by 11436282007 USDC in the incident transaction.
The economic enabler was the price gap between the Morpho oracle and the public AMM. Auditor observations show the oracle valued USR at about 1 USDC, while the attack path could buy USR materially below that price from the public stable pool. That let the attacker obtain enough collateral cheaply to borrow the USDC used in the toxic supply injection, making the accounting inflation realizable end-to-end by any unprivileged searcher.
The adversary cluster consists of EOA 0xd26fd6c406195fc799359fdd00bbfe6e3a75378f and helper contract 0xa85f4f524d15edf3c93dc17a58eb60b386746ce8. The deployment transaction 0x64194376ee50c0cbeee5d8e60b8d89249ac7bf9e5a0e09ba9c12f63a0ad714bb created the helper contract, and the receipt emitted OwnershipTransferred(0x0, 0xd26f...), tying control of the helper to the EOA.
The exploit transaction 0x8673e095c323f6327cef4e2e6355e132184d2da85f21202fb4080a1b3b7d76bd executed in one transaction:
The transaction trace and balance diff line up with this flow. The balance diff records a -11436282007 USDC delta on Morpho and a +1436282007 USDC delta on the attacker EOA:
{
"holder": "0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb",
"delta": "-11436282007"
}
{
"holder": "0xd26fd6c406195fc799359fdd00bbfe6e3a75378f",
"delta": "1436282007"
}
The primary measurable loss is USDC depletion from the Morpho / MetaMorpho accounting path. The collected balance diff shows Morpho's USDC balance decreased by 11436282007 units, which is 11,436.282007 USDC at 6 decimals. That amount corresponds to the inflated deposit-to-redeem round trip enabled by the toxic supply position.
The attacker EOA directly realized 1436282007 USDC units, or 1,436.282007 USDC, after routing and acquisition costs. The remaining value was consumed by the collateral-acquisition path and related swap fees needed to transform mispriced public USR liquidity into borrowable oracle-valued collateral.
0x8673e095c323f6327cef4e2e6355e132184d2da85f21202fb4080a1b3b7d76bd0x64194376ee50c0cbeee5d8e60b8d89249ac7bf9e5a0e09ba9c12f63a0ad714bb0x23479229e52ab6aad312d0b03df9f33b46753b5e0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb0xa40e4a5c4ff8ec8ae05648a4f34e02ced8ae9efb0x35e5db674d8e93a03d814fa0ada70731efe8a4b90x833589fcd6edb6e08f4c7c32d4f71b54bda029130xd3ee0a3b349237d68517df30bfb66be971f46ad9