This is a lower bound: only assets with reliable historical USD prices are counted, so the actual loss may be higher.
0x3d5BC3c8d13dcB8bF317092d84783c2697AE9258Ethereum0x4BAa77013ccD6705ab0522853cB0E9d453579Dd4Ethereum0x338EEE1F7B89CE6272f302bDC4b952C13b221f1dEthereumOn Ethereum mainnet, an attacker-controlled contract cluster manipulated Cream Finance's yvCurve collateral price and then borrowed assets against the inflated collateral. The critical setup happened in transaction 0x0fe2542079644e107cbf13690eb9c2c65963ccb79089ff96bfaf8dced2331c92 at block 13499798, where the attacker moved through DAI, yDAI, Curve yPool LP, and Yearn's yvCurve vault before donating Curve LP back to the Yearn vault. That donation doubled the Yearn share-price input used by Cream's oracle path and lifted the market price for cToken 0x4BAa77013ccD6705ab0522853cB0E9d453579Dd4 from 279300989046321 to 558660503801998 in the observed attack window.
After the manipulated collateral state existed, the attacker borrowed assets from Cream in transaction 0x5189ac29b4d7ed7c1e78423f679f376ac0a2b32158349db84b01677f0608aac8 and transferred the stolen balances to the attacker EOA in transaction 0xfa4f9002a6543bbcb596a6b14690bfb71a14a35d3fc9866cacdf0cd581d7c626. The root cause is a protocol-side oracle design failure: Cream trusted a same-sequence price derived from mutable Curve and Yearn state during Comptroller borrow checks.
The affected Cream market was cyvCurve at 0x4BAa77013ccD6705ab0522853cB0E9d453579Dd4. Its underlying token was the Yearn vault yvCurve at 0x4B5BfD52124784745c1071dcB244C6688d2533d3, and that Yearn vault in turn wrapped Curve yPool LP token 0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8. Cream priced this collateral through at , which derived the yvCurve price from Yearn share pricing and Curve yPool on pool .
0xfa4f9002a6543bbcb596a6b14690bfb71a14a35d3fc9866cacdf0cd581d7c626PriceOracleProxy0x338EEE1F7B89CE6272f302bDC4b952C13b221f1dget_virtual_price()0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51Cream's Comptroller logic at implementation 0x7aa375f1fe5e04e18a6b02b4294cfd57ca9f53ba used that oracle output directly during borrow authorization. The collected borrowAllowed excerpt shows that Cream rejects only zero prices and otherwise calls getHypotheticalAccountLiquidityInternal. The collected liquidity excerpt shows that this function reads oracle.getUnderlyingPrice(asset), folds the returned value into tokensToDenom, and then compares aggregate collateral against borrow effects. That architecture means a manipulable collateral price directly increases borrow capacity.
This incident is an ACT attack, not a privileged compromise. The attacker did not need protocol admin rights or non-public data. The exploitable condition was that Cream accepted a same-sequence collateral value built from two mutable accounting layers: Curve yPool virtual price and Yearn vault share price. The attacker could push those inputs with public protocol calls and then immediately rely on the manipulated output in Cream's borrow path. The invariant that failed was simple: collateral priced for borrow authorization must remain manipulation-resistant throughout the adversary's execution sequence. Cream violated that invariant by trusting PriceOracleProxy::getYvTokenPrice() during the same sequence that changed the underlying Curve and Yearn state. Once the oracle overvalued the attacker's cyvCurve collateral, Comptroller admitted borrowing that was not economically backed by realizable collateral value.
The code-level breakpoint is the interaction between Cream's oracle and liquidity engine. In the collected Comptroller excerpt, borrowAllowed calls:
(Error err, , uint256 shortfall) = getHypotheticalAccountLiquidityInternal(
borrower,
CToken(cToken),
0,
borrowAmount
);
Inside the collected liquidity excerpt, the borrow check reads the oracle and prices the collateral:
vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);
vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});
vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice);
vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.cTokenBalance, vars.sumCollateral);
The attack sequence made that oracle price unreliable. In the seed transaction 0x0fe25420..., the attacker EOA 0x24354d31bc9d90f62fe5f2454709c32049cf866b called helper contract 0x961d2b694d9097f35cfffa363ef98823928a330d, previously deployed in transaction 0xd253e3b563bf7b8894da2a69db836a4e98e337157564483d8ac72117df355a9d. The collected helper deployment artifact shows the attacker EOA created both helpers 0x961d...330d and 0xf701...3284, and the creation bytecode preapproved the protocol contracts later used in the exploit path.
During the seed transaction, the helper funded a large DAI-driven state transition into Curve and Yearn. The collected incident summary and trace-backed artifacts show this sequence: large DAI funding, conversion into yDAI, one-sided addition of roughly 451065927891934141488397224 yDAI liquidity into Curve yPool, deposit of roughly 447202022713276945512955672 Curve LP into the Yearn vault, and minting of roughly 446756774416766306389278551 Yearn shares into Cream's cyvCurve market. Later in the same transaction, the attacker redeemed DUSD into yvCurve, withdrew LP from Yearn, and transferred Curve LP back to the Yearn vault address in an amount matching totalAssets(). That donation step is the determinative breakpoint because it raises Yearn's assets-per-share without minting new shares, which inflates the oracle path Cream uses for the collateral market.
The collected borrowing-power snapshot proves the effect. At block 13499797, the market's oracle_getUnderlyingPrice was 279300989046321. At block 13499798, immediately after the seed sequence, the same field was 558660503801998 while the collateral factor remained 750000000000000000. That is the same order-of-magnitude doubling described in the root cause and sufficient to magnify the borrower's recognized collateral value. With that manipulated value in place, Cream's borrow checks saw no shortfall and allowed undercollateralized borrowing.
The borrow trace for transaction 0x5189ac29... shows the exploit landing exactly where the analysis predicts. The trace records Comptroller::borrowAllowed(...), then PriceOracleProxy::getUnderlyingPrice on the cyvCurve market returning 558660563800658, and finally WBTC transfer plus Borrow event emission for 3272902753 satoshis to helper 0x961d...330d. The later withdrawal trace for transaction 0xfa4f9002... shows helper 0x961d...330d transferring FEI, USDC, WBTC, FRAX, and other borrowed assets back to the attacker EOA, completing value extraction.
The attacker flow had three on-chain stages. First, the EOA deployed and controlled the helper contracts needed to batch approvals, state transitions, and withdrawals. Second, the attacker executed the oracle-manipulation setup transaction 0x0fe25420..., which created the cyvCurve collateral position and inflated the Yearn-plus-Curve-derived price inside Cream's oracle path. Third, with the manipulated collateral still recognized by Cream, the attacker borrowed from listed Cream markets in 0x5189ac29... and then swept the helper's balances to the EOA in 0xfa4f9002....
The borrow stage is directly evidenced in the trace excerpt:
Comptroller::borrowAllowed(..., 3272902753)
...
PriceOracleProxy::getUnderlyingPrice(CErc20Delegator: [0x4BAa77013ccD6705ab0522853cB0E9d453579Dd4]) [staticcall]
...
← [Return] 558660563800658
...
emit Borrow(borrower: 0x961D2B694D9097f35cfFfa363eF98823928a330d, borrowAmount: 3272902753, ...)
The extraction stage is equally direct in the withdrawal trace:
0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599::transfer(
0x24354D31bC9D90F62FE5f2454709C32049cf866b,
3272902753
)
The balance-diff artifacts corroborate those transfers. Transaction 0x5189ac29... credits WBTC to helper 0x961d...330d, and transaction 0xfa4f9002... debits WBTC, FEI, USDC, and FRAX from the helper while crediting the attacker EOA. That makes the exploit path end-to-end complete: manipulate collateral pricing, borrow against the inflated valuation, and withdraw the borrowed inventory to the attacker.
The directly reported losses in the validated root cause are:
3272902753 raw units with decimal=83817374503105485458327683 raw units with decimal=181690395696011 raw units with decimal=6782197337841036790998164 raw units with decimal=18The traces and balance diffs show that these assets were first accumulated by the helper contract as borrowed balances and then transferred to the attacker EOA. The impact was therefore not limited to a temporary accounting distortion inside Cream; it resulted in concrete depletion of borrowable market cash and final extraction of tokens from the protocol's reachable asset inventory.
0x0fe2542079644e107cbf13690eb9c2c65963ccb79089ff96bfaf8dced2331c920x5189ac29b4d7ed7c1e78423f679f376ac0a2b32158349db84b01677f0608aac80xfa4f9002a6543bbcb596a6b14690bfb71a14a35d3fc9866cacdf0cd581d7c6260x24354d31bc9d90f62fe5f2454709c32049cf866b0x961d2b694d9097f35cfffa363ef98823928a330d0xf701426b8126BC60530574CEcDCb365D479732840x3d5BC3c8d13dcB8bF317092d84783c2697AE92580x7aa375f1fe5e04e18a6b02b4294cfd57ca9f53ba0x338EEE1F7B89CE6272f302bDC4b952C13b221f1d0x4BAa77013ccD6705ab0522853cB0E9d453579Dd40x4B5BfD52124784745c1071dcB244C6688d2533d30x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51