Themis Oracle Manipulation
Exploit Transactions
0xff368294ccb3cd6e7e263526b5c820b22dea2b2fd8617119ba5c3ab8417403d8Victim Addresses
0x75f805e2fb248462e7817f0230b36e9fae0280fcArbitrum0xc8f42db9eb6ab58bbfa6e2642107a6086cb4473bArbitrum0xe611e633c1e88d4f026fec5bc1e40e8a477f41adArbitrumLoss Breakdown
Similar Incidents
Sturdy LP Oracle Manipulation
41%Sentiment Balancer Oracle Overborrow
40%dForce Oracle Reentrancy Liquidation
39%Rodeo Oracle Shortfall
37%SellToken Reward Oracle Manipulation
32%Aave AMM LP Oracle Manipulation Through Delegated Recursive LP Looping
32%Root Cause Analysis
Themis Oracle Manipulation
1. Incident Overview TL;DR
On Arbitrum transaction 0xff368294ccb3cd6e7e263526b5c820b22dea2b2fd8617119ba5c3ab8417403d8 in block 105524524, an unprivileged attacker used flash-loaned WETH to skew Balancer's wstETH-WETH stable pool, refreshed Themis's Balancer-gauge oracle while that skew was live, and then borrowed WETH against overstated gauge collateral. The same transaction repaid the flash liquidity and left the attacker with realized profits in ETH, USDC, and USDT.
The root cause is a lending-oracle design failure in Themis. Themis trusted a same-transaction LP price derived from live Balancer pool balances, so temporary attacker-controlled balance changes could immediately increase collateral value inside the borrow path.
2. Key Background
Themis is an Aave-style lending market on Arbitrum with reserves such as tArbWETH, tArbDAI, tArbUSDC, tArbUSDT, tArbARB, and tArbWBTC. The affected collateral was Balancer gauge 0x8f0b53f3ba19ee31c0a73a6f6d84106340fadf5f, which represents LP exposure to Balancer pool 0x36bf227d6bac96e2ab1ebb5492ecec69c691943f (wstETH-WETH stable pool). Themis relied on Balancer LP oracle 0x17df2b52f5d756420846c78c69f4fe4ff10e57a4, and its price-oracle layer at 0xc8f42db9eb6ab58bbfa6e2642107a6086cb4473b consumed that LP price during borrow-limit checks in controller 0x75f805e2fb248462e7817f0230b36e9fae0280fc.
The relevant public protocol components identified in the analysis are:
- Themis controller
0x75f805e2fb248462e7817f0230b36e9fae0280fc - Themis price oracle
0xc8f42db9eb6ab58bbfa6e2642107a6086cb4473b - Themis WETH reserve
0xe611e633c1e88d4f026fec5bc1e40e8a477f41ad - Balancer LP oracle
0x17df2b52f5d756420846c78c69f4fe4ff10e57a4 - Themis subaccount proxy
0xde85d18adda9d2b9eafa7dbf0cec5a89119d90f0
The ACT pre-state used in the analysis is Arbitrum immediately before block 105524524 tx index 3, including Themis reserve balances, Balancer pool balances and total supply, Balancer gauge balances, and the public Chainlink feeds for WETH and wstETH. The auditor marked each of the key protocol contracts above as is_verified=false; the exploit analysis therefore relies on the collected trace and runtime behavior rather than verified explorer source for those addresses. The attack still qualifies as ACT because every critical call path used public on-chain entrypoints: Aave V3 flash loans, Uniswap V3 flash liquidity, Balancer joins and swaps, and Themis supply and borrow flows.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK-category oracle-manipulation exploit. Themis priced Balancer gauge collateral from spot Balancer balances that were observable at the exact moment of the borrow, rather than from a manipulation-resistant source such as a TWAP or delayed oracle update. That allowed the attacker to use flash liquidity to push WETH into the wstETH-WETH stable pool, drastically change the pool composition, and immediately force 0x17df...::latestAnswer() to return an inflated LP price. Themis then consumed that inflated LP price through 0xc8f42...::getAssetPrice() during 0x75f805...::borrow(), so the borrow-limit calculation treated the attacker subaccount as if it had much more collateral than it actually did. Once the WETH borrow succeeded, the attacker unwound the Balancer distortion and repaid the flash liquidity, proving that the price increase was transient and fully attacker-controlled. The broken invariant is straightforward: collateral valuation used in health-factor and borrow-limit checks must not be increaseable within the same transaction by temporary pool balance changes under attacker control.
The vulnerable components were:
- Themis controller / borrow path
0x75f805e2fb248462e7817f0230b36e9fae0280fc - Themis price oracle
0xc8f42db9eb6ab58bbfa6e2642107a6086cb4473b - Balancer LP oracle
0x17df2b52f5d756420846c78c69f4fe4ff10e57a4 - Balancer gauge collateral reserve
0x8f0b53f3ba19ee31c0a73a6f6d84106340fadf5f
The exploit required only three public conditions:
- enough temporary WETH liquidity to skew the Balancer pool,
- the ability to make Themis consume the skewed oracle before the skew was reverted,
- the ability to post gauge shares as collateral through the standard Themis proxy/subaccount flow.
The violated security principles are the same ones called out in the root cause artifact:
- do not use flash-loan manipulable spot AMM balances as lending collateral oracles,
- borrow-limit checks must use manipulation-resistant pricing,
- onboarding exotic LP or gauge collateral requires oracle logic that remains valid under large temporary balance swings.
4. Detailed Root Cause Analysis
The collector trace shows the attacker first assembling temporary WETH liquidity from Aave V3 and Uniswap V3. It then set up a fresh Themis subaccount, joined the Balancer pool with 55 WETH, deposited the received BPT into the Balancer gauge, and supplied 54.665092912647660455 gauge shares into Themis as collateral.
The key oracle breakpoint is visible before and after the Balancer skew. Before manipulation, the LP oracle returned a normal baseline value:
0x17df2B52f5D756420846c78c69F4fE4fF10e57A4::latestAnswer()
MetaStablePool::totalSupply() -> 5445998568169458716380
BalancerVault::getPoolTokens(...) -> [wstETH=2423240452850875484052, WETH=2740951628276599438098]
...
<- [Return] 191099705466
After the attacker swapped 39724.937330688241115794 WETH into the Balancer pool, the pool balances and oracle output changed immediately:
BalancerVault::swap(... amountIn = 2423002389146086585543 wstETH ...)
MetaStablePool::onSwap(...) -> 39724937330688241115794
...
0x17df2B52f5D756420846c78c69F4fE4fF10e57A4::latestAnswer()
MetaStablePool::totalSupply() -> 5500663661082106376835
BalancerVault::getPoolTokens(...) -> [wstETH=61447309529146061, WETH=42252095142331057715112]
...
<- [Return] 1468795169887
That inflated LP price was then consumed directly in Themis's borrow path:
0x75F805e2fB248462e7817F0230B36E9Fae0280Fc::borrow(WETH, 317620373410593518825, 2, 0, 0x2132...)
0xC8f42dB9eB6aB58bBFA6E2642107A6086CB4473B::getAssetPrice(0x8F0B53..., 0x2132...)
0x17df2B52f5D756420846c78c69F4fE4fF10e57A4::latestAnswer()
<- [Return] 1468795169887
...
0xe611e633C1E88d4f026fec5Bc1E40E8A477f41aD::transferUnderlyingTo(0x2132..., 317620373410593518825)
This is the concrete code-level breakpoint described in the root cause artifact: latestAnswer() read live Balancer balances, getAssetPrice() consumed the manipulated value, and borrow() trusted it for collateral accounting. Once the WETH borrow completed, the attacker routed the borrowed WETH back out of the subaccount, reversed the Balancer skew, repaid Aave and Uniswap, and kept the residual assets.
The realized-profit predicate is fully supported by the seed balance diff. The sender EOA started with 0.4984956909 ETH, finished with 94.820454696766716128 ETH, and also ended the transaction with 130471.920034 USDC and 58824.329320 USDT. Using the same-transaction Chainlink WETH price 1900.07440273 USD, the collector-backed valuation is:
- pre-tx value:
947.178902150296196157 USD - post-tx value:
369462.16817854604140905305822944 USD - realized delta:
368514.9892763957 USD
The root cause therefore is not the presence of flash loans themselves. Flash liquidity only made the attack large enough to matter; the actual failure was Themis allowing a same-transaction spot LP oracle to determine collateral value.
5. Adversary Flow Analysis
The attacker cluster identified in the artifact is:
0xdb73eb484e7dea3785520d750eabef50a9b9ab33: sender EOA and final profit recipient0x05a1b877330c168451f081bfaf32d690ea964fca: exploit orchestration contract targeted by the seed tx0x33f3fb58ea0f91f4bd8612d9f477420b01023f25: helper contract deployed mid-transaction0x2132d49157d6148dee8753f059fad1c1b09c477c: freshly created Themis subaccount used for collateral and borrowing
The on-chain execution flow is:
- Flash liquidity acquisition. The orchestrator borrows
22000 WETHfrom Aave V3 and another18000 WETHfrom two Uniswap V3 pools. - Collateral setup. The attacker deploys helper
0x33f3..., creates subaccount0x2132...through the public Themis subaccount proxy0xdE85..., joins Balancer with55 WETH, deposits the resulting BPT into the gauge, and supplies54.665092912647660455gauge shares to Themis. - Oracle manipulation. The attacker swaps
39725 WETHinto the BalancerwstETH-WETHstable pool, pushing the LP oracle from191099705466to1468795169887. - Over-borrow. While the manipulated price is still live, Themis lets the subaccount borrow
317.620373410593518825 WETHfromtArbWETH. - Unwind and realization. The attacker reverses the Balancer swap, repays the flash liquidity, and transfers the remaining ETH, USDC, and USDT profit to the originating EOA.
This is a fully permissionless ACT sequence. No admin action, no off-chain privileged data, and no private attacker artifact was required to make the victim protocol consume the manipulated price.
6. Impact & Losses
The conservative realized losses captured in the artifact are:
ETH:94321959005866716128wei (94.321959005866716128 ETH)USDC:130471920034(130471.920034 USDC)USDT:58824329320(58824.329320 USDT)
The exploit-specific protocol loss was the under-collateralized 317.620373410593518825 WETH borrow from Themis WETH reserve 0xe611e633c1e88d4f026fec5bc1e40e8a477f41ad. The broader attacker PnL after unwind is visible in the balance diff:
{
"native_balance_delta_wei": "94321959005866716128",
"usdc_delta": "130471920034",
"usdt_delta": "58824329320"
}
Those values match the root cause artifact's realized-profit section and show that the attacker walked away with material value after every flash-liquidity obligation had been repaid.
7. References
[1]Seed transaction metadata:/workspace/session/artifacts/collector/seed/42161/0xff368294ccb3cd6e7e263526b5c820b22dea2b2fd8617119ba5c3ab8417403d8/metadata.json[2]Seed transaction trace:/workspace/session/artifacts/collector/seed/42161/0xff368294ccb3cd6e7e263526b5c820b22dea2b2fd8617119ba5c3ab8417403d8/trace.cast.log[3]Seed transaction balance diff:/workspace/session/artifacts/collector/seed/42161/0xff368294ccb3cd6e7e263526b5c820b22dea2b2fd8617119ba5c3ab8417403d8/balance_diff.json[4]Collector seed index:/workspace/session/artifacts/collector/seed/index.json[5]Public secondary PoC reference cited by the auditor:https://raw.githubusercontent.com/SunWeb3Sec/DeFiHackLabs/main/src/test/2023-06/Themis_exp.sol
The only exploit transaction required to reproduce the ACT opportunity is:
- Arbitrum
42161:0xff368294ccb3cd6e7e263526b5c820b22dea2b2fd8617119ba5c3ab8417403d8