Open hats-bug-reporter[bot] opened 1 week ago
The spender and receiver are defined in the calldata. The tokens are sent to the handler contract, which acts as both the spender and the receiver. If these are incorrectly specified in the calldata, the following check will cause the transaction to revert:
@PlamenTSV
Github username: @PlamenTSV Twitter username: @p_tsanev Submission hash (on-chain): 0x7bde80ca9b0cca95cb46dc4141b34064c502b3bc29a2b8ea9fc2334237f41a7b Severity: high
Description: Description\ The Enso handler contract is used to handle swaps at Enso's platform, hardcoded at the
SWAP_TARGET
via delegatecalls, since Enso's shortcut function require to be delegatecalled. However, depending on how the calldata for the swap is encoded and the logic behind the Enso swapping works, the resulting swapped tokens may end up in the Rebalancer instead of the intended handler contract.Attack Scenario\ The path I explored with the handler involves updating the token lists:
updateTokens
we update the portfolio list and change their weights_updateWeights
is invoked, pulling the tokens out of the vault and swapping them through the Enso handler contract via an external call.multiTokenSwapAndTransfer
for which:msg.sender
is the Rebalancer contractaddress(this)
is the handler itselfSWAP_TARGET.delegatecall(callDataEnso[i])
would retain the same sender andaddress(this)
, which means that depending on the Enso swap logic and the calldata provided (probably by the front-end), the swap return may end up in the sender - Rebalancer contract instead of the intended EnsoHandler contractuint256 buyBalanceBefore = IERC20Upgradeable(token).balanceOf(address(this))
and subtracting it from the balance after the swap, but the receiver could be themsg.sender
and notaddress(this)
, the swapped return tokens would be stuck in the Rebalancer instead.Attachments
Proof of Concept (PoC) File
Revised Code File (Optional)
Recommendation\
msg.sender
, aka the Rebalancer, not the handler itself, since due to the delegatecall, it is not the handler which receives the tokens_to
address and not from the handler.