Ploutos Market Oracle Feed Misconfiguration Enabled Undercollateralized WETH Borrow
Exploit Transactions
0xa17dc37e1b65c65d20042212fb834974f7faaa961442e3fc05393778705f8474Victim Addresses
0x7398e7e3603119d9241e45f688734436fd7b1540Ethereum0x9dce7a180c34203fee8ce8ca62f244feeb67bd30Ethereum0xd060ebd4f56be8866376a3616b6e5aef87f945d2EthereumLoss Breakdown
Similar Incidents
bZx/Fulcrum iETH oracle manipulation enables undercollateralized WETH borrowing
37%Aave AMM LP Oracle Manipulation Through Delegated Recursive LP Looping
35%bZx/Fulcrum WBTC market manipulation drains ETH liquidity
34%Curve crvUSD sDOLA Market In-Tx Oracle Refresh Liquidation Attack
33%WETH Drain via Unprotected 0xfa461e33 Callback on 0x03f9-62c0
31%P2Controller/XNFT BAYC Over-Borrow via Per-Order-Only Collateral
30%Root Cause Analysis
Ploutos Market Oracle Feed Misconfiguration Enabled Undercollateralized WETH Borrow
1. Incident Overview TL;DR
In Ethereum block 24538897, an unprivileged adversary executed transaction 0xa17dc37e1b65c65d20042212fb834974f7faaa961442e3fc05393778705f8474 against Ploutos Market (0x7398e7e3603119d9241e45f688734436fd7b1540) and drained most borrowable WETH by posting only 8.879192 USDC collateral.
The borrow passed because the protocol oracle (0x9dce7a180c34203fee8ce8ca62f244feeb67bd30) priced USDC using the BTC/USD feed (0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c). This mapping was set in the prior block by transaction 0xcfedf63b37a6cd45b21bc94e3de5412fee0765e7dad6b7c8561a01cebd193ab6.
Root cause: AaveOracle accepted an incompatible source assignment (USDC -> BTC/USD) and getAssetPrice returned raw latestAnswer() without semantic validation/sanity bounds, so collateral valuation became deterministically incorrect.
This is an ACT case: one public transaction by an unprivileged EOA realized the exploit predicate and netted 181.745096492453810260 ETH.
2. Key Background
Ploutos uses an Aave v3-style valuation path where collateral and debt checks call AaveOracle.getAssetPrice(asset) and compare normalized values in a common base currency (BASE_CURRENCY_UNIT = 1e8).
Relevant components:
- Pool proxy (victim path):
0x7398e7e3603119d9241e45f688734436fd7b1540 - Oracle:
0x9dce7a180c34203fee8ce8ca62f244feeb67bd30 - Collateral token: USDC
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 - Borrowed token: WETH
0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - Misconfigured feed: BTC/USD
0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c
Exploit pre-state (just before block 24538897) is publicly reconstructible and already contains the wrong USDC source from tx 0xcfedf63b... in block 24538896.
3. Vulnerability Analysis & Root Cause Summary
Root cause category: ATTACK.
The protocol safety invariant is: each listed asset must map to a semantically correct oracle feed for that asset at the expected base-currency scale. Borrow safety inherits this assumption.
The concrete code-level breakpoint is in AaveOracle:
_setAssetsSourceswritesassetsSources[asset] = AggregatorInterface(source)with no asset/feed compatibility checks.getAssetPricereturnsuint256(source.latestAnswer())when positive, with no semantic sanity guard that USDC is actually mapped to a USD-stable feed.
As a result, when USDC was mapped to BTC/USD, borrow logic treated 8.879192 USDC as extremely valuable collateral and allowed borrowing 187.366746326704993556 WETH.
4. Detailed Root Cause Analysis
4.1 Victim code mechanism
Oracle implementation confirms the vulnerable behavior:
function _setAssetsSources(address[] memory assets, address[] memory sources) internal {
require(assets.length == sources.length, Errors.INCONSISTENT_PARAMS_LENGTH);
for (uint256 i = 0; i < assets.length; i++) {
assetsSources[assets[i]] = AggregatorInterface(sources[i]);
emit AssetSourceUpdated(assets[i], sources[i]);
}
}
function getAssetPrice(address asset) public view override returns (uint256) {
AggregatorInterface source = assetsSources[asset];
...
int256 price = source.latestAnswer();
if (price > 0) {
return uint256(price);
} else {
return _fallbackOracle.getAssetPrice(asset);
}
}
The assignment and read paths are independent of asset/feed semantic correctness.
4.2 Deterministic precondition creation
In tx 0xcfedf63b37a6cd45b21bc94e3de5412fee0765e7dad6b7c8561a01cebd193ab6, oracle event data shows:
AssetSourceUpdated(asset=USDC, source=0xF403...E88c)
Independent state calls at block 24538897 confirm:
getSourceOfAsset(USDC) = 0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c- Feed
description() = "BTC / USD" - Feed
latestAnswer() = 6855405329514
4.3 Exploit execution and borrow acceptance
Seed trace shows the atomic flow:
UniswapV2Pair::swap(8879192, ...) -> attackerContract::uniswapV2Call(...)
Pool::deposit(USDC, 8879192, attackerContract, 0)
Pool::borrow(WETH, 187366746326704993556, 2, 0, attackerContract)
AaveOracle::getAssetPrice(USDC) -> BTC/USD latestAnswer -> 6855405329514
AaveOracle::getAssetPrice(WETH) -> ETH/USD latestAnswer -> 208047000000
Because USDC price was massively inflated relative to WETH, the health-factor and borrow checks passed.
4.4 Settlement and realized predicate
The same transaction then:
- repaid only
0.004289216474598283WETH to the pair, - unwrapped
187.362457110230395273WETH, - transferred
5.612909926920174741ETH to builder address0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97, - transferred
181.749547183310220532ETH to attacker EOA0x3885869b0f4526806b468a0c64a89bb860a18cee.
Balance deltas give the deterministic net result (after gas/transfers):
- attacker EOA native balance delta:
+181.745096492453810260 ETH - WETH contract native delta (proxy for protocol-side WETH outflow in this flow):
-187.362457110230395273 ETH
4.5 ACT exploit conditions
The opportunity exists when all of the following hold:
- USDC source is mapped to a high-valued non-USDC feed with positive answer.
- Pool has material WETH liquidity.
- Adversary can source small USDC atomically and perform deposit+borrow in one tx.
All conditions were satisfied at block 24538897.
5. Adversary Flow Analysis
Adversary-related accounts:
- EOA
0x3885869b0f4526806b468a0c64a89bb860a18cee: seed tx sender and final ETH recipient. - Contract
0x3e47945cca05439f99029a3d21e3166ce1a84fab: executes flash-swap callback, collateral deposit, borrow, repayment, unwrap, and payout.
End-to-end lifecycle:
- Precondition (victim-observed): tx
0xcfedf63b...remaps USDC source to BTC/USD. - Atomic exploit: tx
0xa17dc37e...executes flash swap -> deposit USDC -> borrow WETH while oracle is misconfigured. - Profit realization: attacker repays minimal flash leg, unwraps WETH, pays builder, and exits with net ETH profit.
6. Impact & Losses
Measured impact:
- Primary reserve depletion:
187.362457110230395273 WETH - Net attacker profit:
181.745096492453810260 ETH
Affected parties/components:
- Ploutos lending pool WETH reserve (
aWETH/pool liquidity path) - Borrow-risk controls that trusted mutable oracle source mapping without semantic guardrails
Exposure closure:
- A later corrective transaction (
0xee3d7556528d3ceb00681a3c7ed7be3751c83923675bc3774c77f9f4e60d20f0) remapped USDC to the intended feed.
7. References
- Seed exploit tx:
0xa17dc37e1b65c65d20042212fb834974f7faaa961442e3fc05393778705f8474 - Misconfiguration tx:
0xcfedf63b37a6cd45b21bc94e3de5412fee0765e7dad6b7c8561a01cebd193ab6 - Correction tx:
0xee3d7556528d3ceb00681a3c7ed7be3751c83923675bc3774c77f9f4e60d20f0 - Oracle contract:
0x9dce7a180c34203fee8ce8ca62f244feeb67bd30 - Pool proxy:
0x7398e7e3603119d9241e45f688734436fd7b1540 - BTC/USD feed used for USDC:
0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c - Local evidence artifacts:
- seed trace (
trace.cast.log) - seed balance deltas (
balance_diff.json) - seed metadata (
metadata.json)
- seed trace (
- Public code source (AaveOracle implementation): Sourcify full-match source for
0x9dce....