Normal behavior: The protocol uses the 1inch aggregation router to swap tokens during open and unwind flows. The position owner passes _oneInchSwapData (calldata from the 1inch API or equivalent) so the contract can execute the swap on their behalf. The router address is set at initialization and trusted.
The swapData parameter is fully user-supplied (position owner supplies it in createLeveragedPosition and unwindPosition). It is forwarded as raw calldata to the 1inch router via a low-level call. The 1inch AggregationRouter is designed to execute arbitrary external calls as part of swap descriptions (e.g. DEX hops, executor callbacks). An attacker (malicious owner or compromised owner) can pass swapData that routes through a malicious token or contract that calls back into Stratax during the swap. The contract has no reentrancy guard, so a mid-swap reentrant call can drain funds (e.g. recoverTokens) or corrupt state.
Likelihood:
The position owner (or an attacker who compromises the owner) controls the swapData. Off-chain 1inch API typically returns benign routes, but the owner can substitute custom calldata that encodes a route through a malicious contract (e.g. a custom "pool" or token that implements a callback).
1inch routers accept swap descriptions that include executor-style or protocol calls to arbitrary addresses. Routing through a contract that re-enters Stratax is feasible.
Impact:
During the 1inch swap, a malicious contract in the route can re-enter Stratax (e.g. call recoverTokens, or in a different flow createLeveragedPosition / unwindPosition). The contract holds user collateral, borrowed tokens, or flash-loaned assets at that moment; recoverTokens can drain them to the owner (attacker).
Reentrancy can leave storage or accounting inconsistent (e.g. nested flash loan callback, double supply/withdraw assumptions), leading to stuck positions or further exploitation.
The PoC uses a minimal Victim contract that mirrors Stratax (router.call(userSuppliedSwapData), recoverTokens, no reentrancy guard). A MaliciousRouter implements executeCallback(target, data) so that user-supplied swapData can tell the "router" to call an arbitrary contract. The attacker supplies swapData that instructs the router to call ReenterContract.attack(victim, token, amount). That call re-enters Victim.recoverTokens and drains the victim's token balance to the owner (here the reenter contract, which then forwards to the attacker).
Add a reentrancy guard (e.g. OpenZeppelin ReentrancyGuard and nonReentrant modifier) on all external entry points that eventually call _call1InchSwap (createLeveragedPosition, unwindPosition), and on recoverTokens, so that mid-swap reentrancy is blocked.
Where feasible, restrict what the swapData can do: e.g. validate that the 1inch router is only called with swap descriptions that do not include arbitrary executor calls, or use a dedicated router wrapper that only allows a whitelist of operations. This is protocol-specific and may require 1inch integration changes.
As a defense-in-depth, ensure critical state changes (e.g. token transfers out via recoverTokens) follow checks-effects-interactions and consider a short lock or delay for recoverTokens so that it cannot be used in the same reentrant call stack as an in-flight swap.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.