No token-level loss is recorded for this incident.
No token-level loss detail has been recorded for this incident yet.
0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2Ethereum0xe1d97bf61901b075e9626c8a2340a7de385861efEthereumIn block 24626860, Chainlink upkeep tx 0x32c64151469cf2202cbc9581139c6de7b34dae2012eba9daf49311265dfe5a1e refreshed Aave's WstETHPriceCapAdapter at 0xe1d97bf61901b075e9626c8a2340a7de385861ef. The refresh lowered the adapter's latestAnswer() from 253475871245 at block 24626859 to 246276569349 at block 24626860, which immediately pushed some wstETH-backed Aave positions into liquidation range. Because Aave V3 Pool::liquidationCall(address,address,address,uint256,bool) is permissionless, any searcher able to source temporary WETH could realize the spread. Tx 0x9064b507f16bd8b85fb5aea0185153b01fa23b3205f7153f986e5107ce988a9c did exactly that in the same block with a flash-loan-backed liquidation and realized 83.237351108632291961 ETH of net cluster profit after fees. This is an ACT MEV opportunity, not a protocol code bug.
Aave V3 Ethereum prices wstETH through the CAPO adapter at 0xe1d97bf61901b075e9626c8a2340a7de385861ef. The adapter takes an ETH/USD base price and a capped wstETH/stETH ratio and exposes the result through latestAnswer(). Chainlink automation updates the adapter by calling KeeperRegistry transmit(bytes32[3],bytes,bytes32[],bytes32[],bytes32), which routes through and into the adapter's cap-parameter update path.
ChainlinkAgentHubAaveCapoAgentAave liquidations are intentionally permissionless. Once a borrower's health factor drops below 1e18, any unprivileged caller can repay eligible debt through liquidationCall, seize discounted collateral, and finance the repayment leg with flash liquidity. In this incident, the relevant public components were the Aave pool at 0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2, the wstETH CAPO adapter, the KeeperRegistry at 0x6593c7de001fc8542bb1703532ee1e5aa0d458fd, Balancer's vault at 0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb, and on-chain swap paths that let liquidators unwind seized wstETH back into WETH or ETH.
The root cause category is MEV. No contract invariant in Aave or Chainlink was broken; the system behaved as designed. The decisive state transition was the public CAPO refresh, which changed the adapter snapshot parameters and lowered the collateral price used by Aave for wstETH. That price move created a deterministic liquidation window for accounts that were healthy before the upkeep and unhealthy after it. Because the refresh transaction and the resulting oracle state were public, any searcher observing block construction could immediately submit a liquidation transaction. The profit came from the liquidation discount after sourcing temporary WETH, repaying the user's debt, seizing wstETH, unwinding it on-chain, and paying inclusion costs.
The seed upkeep trace shows the exact call path that matters:
ChainlinkAgentHub::performUpkeep(...)
AaveCapoAgent::inject(...)
wsteth_adapter::setCapParameters(
snapshotRatio: 1191926196478762900,
snapshotTimestamp: 1772535647,
maxYearlyRatioGrowthPercent: 880
)
emit CapParametersUpdated(...)
This trace evidence matches the supporting RPC observations for the adapter:
{
"latest_answer_by_block": {
"24626859": "253475871245",
"24626860": "246276569349"
},
"snapshot_ratio_by_block": {
"24626859": "1157209899495068171",
"24626860": "1191926196478762900"
}
}
The analysis in root_cause.json correctly identifies the breakpoint as PriceCapAdapterBase._setCapParameters, because that state change feeds the adapter's latestAnswer() calculation and directly lowers the collateral value Aave consumes.
The price drop translated into lower health factors for wstETH-backed Aave accounts. The clearest end-of-block evidence is user 0x4bacce55f0991cfc4d919f7f50edb8be028e37df:
{
"24626859": {
"healthFactor": "1022402425563995375"
},
"24626860": {
"healthFactor": "993363819600238528"
},
"24626861": {
"healthFactor": "1027227676630100074"
}
}
That sequence shows the user healthy before the refresh, unhealthy after the refresh, and healthy again after liquidation in the next block. The report in root_cause.json also cites user 0x4f962bb0ea0785c539f8ab52a17f1f873ddc355f as a same-block liquidation example. That is consistent with tx 0x9064... being mined at transaction index 1 in block 24626860: by the end of the block the user's account-level state had already been partially repaired by liquidation, so the end-of-block health factor alone cannot show the transient intra-block unhealthy state.
The attacker-crafted tx 0x9064b507f16bd8b85fb5aea0185153b01fa23b3205f7153f986e5107ce988a9c proves the realization path. The receipt and the supporting observations show:
{
"flashloan_event": {
"address": "0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb",
"event": "FlashLoan(address,address,uint256)",
"amount": "6304565167623755951957"
},
"liquidation_event": {
"pool": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
"collateralAsset": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0",
"debtAsset": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"user": "0x4f962bb0ea0785c539f8ab52a17f1f873ddc355f",
"debtToCover": "6304565167623755951957",
"liquidatedCollateralAmount": "5327964413223143335971"
}
}
That transaction was sent by EOA 0x07de4e70ff80bc47546ef7c5d081a4a1ff8bd98e to helper contract 0xbd32122bad41a09f2405bb374a83877d8245079c. The helper received the seized wstETH, unwound it, repaid the flash loan, and retained the profit. A second liquidation tx, 0x8f47b5e821530e9b9fc2262cde6dbb7427311f13116de995650fd7709df2fa67, liquidated 0x4bacce... in block 24626861, confirming that the opportunity was repeatable and permissionless rather than attacker-specific.
The adversary flow has three stages.
First, the victim-observed upkeep tx publicly updates the CAPO adapter. The transaction is a normal Ethereum type-2 tx from Chainlink transmitter 0x1916cd78cc243e631edfea853dfa85989dcc5edd into KeeperRegistry 0x6593c7de001fc8542bb1703532ee1e5aa0d458fd, so any searcher with standard mempool or block-building visibility can observe it.
Second, the adversary submits a liquidation transaction immediately after the refresh. In tx 0x9064..., the attacker sources WETH through a Balancer flash loan, calls Aave liquidationCall, and receives wstETH collateral through helper contract 0xbd32122bad41a09f2405bb374a83877d8245079c.
Third, the adversary unwinds the collateral and realizes profit. The supporting observations attribute +83.237387877235800171 ETH to the helper contract, -0.000036768603508210 ETH in gas to the sender EOA, and 157.333019847920248526 ETH paid to the block builder, for a net cluster gain of 83.237351108632291961 ETH after fees. Those numbers are consistent with a searcher monetizing a public liquidation window rather than exploiting broken accounting or privileged access.
No protocol-level asset theft or broken accounting was identified, so total_loss_overview is empty in the source artifact and metadata.json records no direct loss entries. The impact is economic: borrowers whose positions crossed below health factor 1 after the oracle refresh became permissionlessly liquidatable, and searchers captured the liquidation spread. The two concrete affected accounts cited in the analysis are 0x4f962bb0ea0785c539f8ab52a17f1f873ddc355f and 0x4bacce55f0991cfc4d919f7f50edb8be028e37df.
0x32c64151469cf2202cbc9581139c6de7b34dae2012eba9daf49311265dfe5a1e0x9064b507f16bd8b85fb5aea0185153b01fa23b3205f7153f986e5107ce988a9c0x8f47b5e821530e9b9fc2262cde6dbb7427311f13116de995650fd7709df2fa670x6593c7de001fc8542bb1703532ee1e5aa0d458fd0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e20xe1d97bf61901b075e9626c8a2340a7de385861ef0x32c64151469cf2202cbc9581139c6de7b34dae2012eba9daf49311265dfe5a1e