The tradeAll parameter of the swap() function in the modules can be exploited to drain any existing locked tokens of the Executioner contract. This behavior effectively nullifies the access control for rescueTokens(), except for the native token case.
Scenario
Suppose the Executioner contract happens to hold a number of X tokens for some reasons (e.g., users accidentally “donating” funds to it, or leftovers of previous trades having accumulated).
Then, adversaries can call executeTrades() where the first element of trades is given the calldata for a swap() call with tradeAll == true and tokenIn == X.
Then, the first swap() call will swap all the X tokens held by the Executioner contract, and return the swapped output to the adversaries.
Recommendation
For the short term, clearly document this behavior so that users take extra caution to not leave any leftovers nor accidently “donating” funds to Executioner.
For the long term, improve the contract logic so that each trades[i] execution can be given the result of the previous trades[j] for j < i, and the tradeAll logic can utilize the historical information.
Handle
daejunpark
Vulnerability details
Impact
The
tradeAll
parameter of the swap() function in the modules can be exploited to drain any existing locked tokens of the Executioner contract. This behavior effectively nullifies the access control for rescueTokens(), except for the native token case.Scenario
executeTrades()
where the first element oftrades
is given the calldata for a swap() call withtradeAll == true
andtokenIn == X
.Recommendation
For the short term, clearly document this behavior so that users take extra caution to not leave any leftovers nor accidently “donating” funds to Executioner.
For the long term, improve the contract logic so that each
trades[i]
execution can be given the result of the previoustrades[j]
forj < i
, and thetradeAll
logic can utilize the historical information.