OracleUpgradeable.getPriceInWeth reads the instantaneous reserve ratio of a TSwap pool, and ThunderLoan.getCalculatedFee prices every flash loan directly from it. There is no TWAP, no Chainlink feed, and no sanity bound, so the fee is whatever the pool's spot price says at that exact moment. A swap executed in the same transaction moves that ratio, so the borrower controls the fee he pays.
Likelihood: High
An attacker needs no capital and no special privileges: the manipulating swap can itself be funded by the flash loan being taken. Any TSwap pool used by the oracle can be moved by anyone within a single transaction, and the attack is repeatable every block.
Impact: High
The flash loan fee is the only mechanism that raises the AssetToken exchange rate. Suppressing it steals yield directly from liquidity providers and drains protocol revenue indefinitely.
Seed a TSwap pool at 100 tokenA : 100 WETH, quote the fee, dump tokenA into the pool, quote again.
Result:
Replace the spot-price read with a manipulation-resistant source. A spot price reflects a single instant and can be moved by any swap in the same transaction, so it must never price a fee that the same transaction pays. A time-weighted average price (TWAP) accumulated over several blocks forces an attacker to hold the manipulated price across blocks, which exposes the position to arbitrage and makes the attack uneconomic. A Chainlink feed with a staleness check removes the dependency on pool reserves entirely and is preferable where a feed exists for the token.
If the protocol must keep reading from TSwap, the minimum safe form is to read both the spot price and a TWAP, then revert when they diverge by more than a configured tolerance. That bound makes a single-transaction swap unable to move the quoted fee, since any manipulation large enough to matter also breaks the deviation check. The fix below applies this approach.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.