flashloan() reads startingBalance at line 182 before making three external calls (updateExchangeRate, transferUnderlyingTo, executeOperation). The repayment check at line 213 compares endingBalance against this stale startingBalance.
Additionally, the reentrancy guard s_currentlyFlashLoaning[token] = true is set at line 198 — after the first external call at line 194 — violating the Checks-Effects-Interactions (CEI) pattern.
During the executeOperation callback (line 201), a malicious receiver can call deposit() on the same token. This increases the pool's token balance, making endingBalance >= startingBalance + fee pass — even though the actual loan principal was never repaid.
Likelihood:
The attack requires no privileged access; any address that deploys a contract implementing IFlashLoanReceiver can execute it. The vulnerable path is triggered on every flashloan() call.
Impact:
A malicious borrower can take a flash loan and never repay the principal, draining the entire token balance of the pool. All LP funds for that token are at risk.
Follow the CEI strictly set s_currentlyFlashLoaning[token] = true before any external call.
Move updateExchangeRate(fee) to after the repayment check, so the balance snapshot is taken immediately before the check.
Consider using OpenZeppelin ReentrancyGuard (nonReentrant) on flashloan(), deposit(), and redeem() to prevent cross-function reentrancy.
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.