Thunder Loan

AI First Flight #7
Beginner FriendlyFoundryDeFiOracle
EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Per-token flash loan flag does not guard redeem(), enabling cross-function reentrancy to extract inflated yield during callback

Root + Impact

Description

  • flashloan sets s_currentlyFlashLoaning[token] = true during the callback to prevent recursive flash loans for the same token. This per-token flag is the only reentrancy protection in the contract.

  • The flag does not guard redeem(), deposit(), or any other state-modifying function. Combined with the CEI violation in H-4 (exchange rate inflated before the callback), an LP who is also a flash loan borrower can call redeem() inside executeOperation at the pre-earned inflated rate, extracting more underlying tokens than they deposited.

// flashloan:
s_currentlyFlashLoaning[token] = true;
assetToken.transferUnderlyingTo(receiverAddress, amount);
@> receiverAddress.functionCall(...); // callback — redeem() is unguarded here
// redeem():
function redeem(IERC20 token, uint256 amountOfAssetToken)
external
revertIfZero(amountOfAssetToken)
revertIfNotAllowedToken(token)
// No s_currentlyFlashLoaning check — fully callable during callback
{
AssetToken assetToken = s_tokenToAssetToken[token];
@> uint256 exchangeRate = assetToken.getExchangeRate(); // reads inflated rate from H-4
...
}

Risk

Likelihood:

  • Any LP who also initiates a flash loan — a natural combination in a lending protocol — can execute this attack.

  • The attack is amplified by H-4 (CEI violation) and H-1 (deposit bypass); together these create a compounded exploit path within a single callback.

Impact:

  • Cross-function reentrancy during the callback enables LP-borrowers to extract yield before it is earned, at the expense of other LPs.

  • The per-token flag creates a false sense of reentrancy safety while leaving every other state-modifying function in the protocol exposed during callback execution.

Proof of Concept

Place this test in test/ and run forge test --match-test testCrossFunctionReentrancy. The test demonstrates that a malicious flash loan receiver can call redeem() during the executeOperation callback because there is no cross-function reentrancy guard, extracting inflated token amounts.

contract CrossFunctionReentrancyAttack is IFlashLoanReceiver {
ThunderLoan thunderLoan;
IERC20 token;
AssetToken assetToken;
function attack(uint256 amount) external {
// Precondition: hold AssetTokens from prior deposit
thunderLoan.flashloan(address(this), token, amount, "");
}
function executeOperation(
address _token, uint256 amount, uint256 fee,
address, bytes calldata
) external returns (bool) {
// Exchange rate already inflated (H-4 CEI violation)
// redeem() is not guarded by s_currentlyFlashLoaning
uint256 assetBalance = assetToken.balanceOf(address(this));
thunderLoan.redeem(IERC20(_token), assetBalance); // redeem at inflated rate
// Then repay flash loan
IERC20(_token).approve(address(thunderLoan), amount + fee);
thunderLoan.repay(IERC20(_token), amount + fee);
return true;
}
}

Recommended Mitigation

Inherit ReentrancyGuardUpgradeable and apply nonReentrant to both flashloan() and redeem() so the cross-function reentrancy path is blocked at the modifier level.

+ import {ReentrancyGuardUpgradeable} from
+ "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
contract ThunderLoan is ... ReentrancyGuardUpgradeable {
+ function flashloan(...) external nonReentrant { ... }
+ function deposit(...) external nonReentrant { ... }
+ function redeem(...) external nonReentrant { ... }
}

The s_currentlyFlashLoaning per-token flag can be retained for the semantic check (e.g., blocking deposits during active flash loans per H-1 fix), but it is not a substitute for a full reentrancy guard.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 7 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!