Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: high
Likelihood: high

Reentrancy in Flash Loan Operations

Author Revealed upon completion

Root + Impact

Description

  • Flash loan operations should complete atomically with all state changes finalized before external calls to untrusted contracts.

  • The contract makes external calls to the 1inch router and performs token approvals before completing critical state changes, allowing potential reentrancy attacks during the swap execution.

function _executeOpenOperation(address _asset, uint256 _amount, uint256 _premium, bytes calldata _params)
internal
returns (bool)
{
// ... code ...
// @> External call to untrusted 1inch router before all state is finalized
uint256 returnAmount =
_call1InchSwap(flashParams.oneInchSwapData, flashParams.borrowToken, flashParams.minReturnAmount);
// @> State changes happen after external call
uint256 afterSwapBorrowTokenbalance = IERC20(flashParams.borrowToken).balanceOf(address(this));
require(afterSwapBorrowTokenbalance == prevBorrowTokenBalance, "Borrow token left in contract");
}
function _call1InchSwap(bytes memory _swapParams, address _asset, uint256 _minReturnAmount)
internal
returns (uint256 returnAmount)
{
// @> Low-level call to external contract with user-controlled data
(bool success, bytes memory result) = address(oneInchRouter).call(_swapParams);
require(success, "1inch swap failed");
}

Risk

Likelihood:

  • User-controlled _swapParams data is passed directly to 1inch router via low-level call

  • Malicious user could craft swap data that calls back into the contract during execution

  • No reentrancy guards (nonReentrant modifier) are implemented

Impact:

  • Attacker could manipulate contract state during callback

  • Multiple flash loans could be initiated simultaneously

  • Funds could be drained through recursive calls

  • Health factor checks could be bypassed

Proof of Concept

// Attacker contract
contract Exploit {
Stratax public stratax;
bool public attacked;
function attack() external {
// Craft malicious swap data that calls back to this contract
bytes memory maliciousSwapData = abi.encodeWithSelector(
this.callback.selector
);
stratax.createLeveragedPosition(
collateralToken,
flashAmount,
userCollateral,
borrowToken,
borrowAmount,
maliciousSwapData,
minReturn
);
}
function callback() external {
if (!attacked) {
attacked = true;
// Reenter during swap execution
stratax.createLeveragedPosition(...);
}
}
}

Recommended Mitigation

+ import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
- contract Stratax is Initializable {
+ contract Stratax is Initializable, ReentrancyGuardUpgradeable {
function createLeveragedPosition(
address _flashLoanToken,
uint256 _flashLoanAmount,
uint256 _collateralAmount,
address _borrowToken,
uint256 _borrowAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
- ) public onlyOwner {
+ ) public onlyOwner nonReentrant {
function unwindPosition(
address _collateralToken,
uint256 _collateralToWithdraw,
address _debtToken,
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
- ) external onlyOwner {
+ ) external onlyOwner nonReentrant {
+ import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
- contract Stratax is Initializable {
+ contract Stratax is Initializable, ReentrancyGuardUpgradeable {
function createLeveragedPosition(
address _flashLoanToken,
uint256 _flashLoanAmount,
uint256 _collateralAmount,
address _borrowToken,
uint256 _borrowAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
- ) public onlyOwner {
+ ) public onlyOwner nonReentrant {
function unwindPosition(
address _collateralToken,
uint256 _collateralToWithdraw,
address _debtToken,
uint256 _debtAmount,
bytes calldata _oneInchSwapData,
uint256 _minReturnAmount
- ) external onlyOwner {
+ ) external onlyOwner nonReentrant {

Support

FAQs

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

Give us feedback!