Closed code423n4 closed 2 years ago
In context of contest readme: "rescueTokens and rescueTokensFromExecutioner can be gamed however it is not a concern. They are in place "just in case" and should not be used in the first place."
finding is invalid/out of scope.
Dispute accepted.
Handle
zer0dot
Vulnerability details
Impact
This vulnerability allows any trade to effectively drain the balance, as long as it is not the chain's native asset (which is not used directly in the modules) , from the Executioner.sol contract. This is technically not critical because funds are not supposed to remain in the Executioner.sol contract.
However, the existence of the
rescueTokens()
function may be redundant, and its execution may be frontrun if an attacker is aware of this vulnerablity.Proof of Concept
Here is how an attack would unfold:
Aassume DAI balance of Executioner = 1, the attack is successful if the 1 DAI is drained, used values are just for the sake of the example:
fromToken = DAI
,fromAmount = 0.001
andtoToken = USDC
0.001 + 1 = 1.001 DAI
in thetrade.encodedCallData
variable, ortradeAll = true
.toToken
(USDC) will equal 0 b._transferFromOrWrap
will transfer 0.001 DAI to the Executioner c.executioner.executeTrades(trades)
will execute the trade with encoded calldata, trading 1.001 DAI for, for example, 1.001 USDC d.finalOutputAmount
will equal1.001 - 0 = 1.001 USDC
e.executioner.sendFunds(toToken, _msgSender(), finalOutputAmount)
will transfer 1.001 USDC to the original message sender, effectively draining the executioner's balance.Recommended Mitigation Steps
The ideal mitigation would be to not allow user-crafted calldata to be executed via delegateCall on the modules from the Executioner contract. This would ensure that the trade parameters passed to the original
executeTrades()
function in the Slingshot.sol contract are the ones that are used for the actual swap.