Open code423n4 opened 2 years ago
Not sure I agree with the mitigation (perhaps a better alternative would be to transfer the balance of the executor), but understand the problems!
Upon further reflection, choosing to remove support for fee on transfer tokens. The problems are much deeper than just issues on execute
-- the minted token will not have fees on transfers (uses vanilla ERC20 implementation), and i doubt the StableSwap
implementations are taking these into account as well. Changing label to "acknowledged"!
The destination chain will indeed be unable to handle bridge transfers involving fee-on-transfer tokens. Although, its worth adding that this is only made possible because handleIncomingAsset
and swapToLocalAssetIfNeeded
in xcall
do not fail when the provided asset has some fee-on-transfer behaviour.
Because _args.amount
is not overridden with the actual amount
transferred in from handleIncomingAsset
, routers on the destination chain will attempt to provide liquidity for the amount transferred by the user + the fee. Furthermore, when the transfer has been fully bridged, routers who fronted the liquidity will receive less funds than expected. However, I don't actually think this issue warrants high
severity, mainly because the bridge transfer should actually execute successfully.
The only issue is that if routers front liquidity, they are exposing themselves to receiving slightly less funds due to the fee upon reconciliation. Hence, only value is being leaked and I think medium
severity makes more sense.
Lines of code
https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L856-L877 https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L142-L144 https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L160-L166 https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L194-L213
Vulnerability details
Impact
_handleExecuteTransaction may not working correctly on fee-on-transfer tokens. As duplicated fee is applied to fee on transfer token when executing a arbitrary call message passing request. Moreover, the Executor contract increase allowance on that token for that target contract in full amount without any fee, this may open a vulnerability to steal dust fund in the contract
Moreover, failure is trying to send full amount without any fee which is not possible because fee is already applied one time for example 100 Safemoon -> 90 Safemoon but trying to transfer 100 safemoon to _recovery address. Obviously not possible since we only have 90 Safemoon. This will revert and always revert causing loss of fund in all case of fee-on-transfer tokens.
Proof of Concept
A message to transfer 100 Safemoon with some contract call payload has been submitted by a relayer to _handleExecuteTransaction function on BridgeFacet these lines hit.
Noticed that 100 Safemoon is transferred to executor before contract execution. Now executor has 90 Safemoon due to 10% fee on transfer.
Next, we increase allowance of target contract to transfer 100 more Safemoon.
After that, it call target contract
Target contract tried to pull 100 Safemoon from Executor but now Executor only has 90 Safemoon, so contract call failed. Moving on to the failure handle.
isNative = false because of Safemoon
Trying to transfer 100 Safemoon to _recovery while only having 90 Safemoon in the contract. Thus failure handle is reverted.
Tools Used
Manual
Recommended Mitigation Steps
You should approve one step only. Avoid an extra token transfer.