-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Current implementation of arbitrary call execute failure handler may break some use case for example NFT bridge. #223
Comments
Acknowledge that this should be an issue, but think that the UX of having to submit multiple destination chain transactions is not great (and causes problems with fees / assuming the user has gas on the destination domain). I think this type of thing needs to be handled by the integrator themselves |
I have reviewed this once again and found another case that Current implementation of arbitrary call execute failure handler may break some use case for example NFT bridge. The idea for this to happened is simply do anything to set It would be better to revert and allow it to be executed again in the future by simply revert in case of arbitrary call failed. If the destination contract is upgradable, it can be fixed but if not it is out of luck. But current implementation is out of luck in all case. Anyway, the sudden gas price increase problem can't be handled accurately as its may happened very fast. (5 gwei 2 minutes ago, 50 gwei when the NFT unlock as a big NFT project is minting). No one will spare that much gas while locking NFT in the source chain 2 minutes ago. |
Gas limit does not change deterministically. If you make a call which provides X amount of gas at Y price, if gas price changes, it will not affect any pending calls. The issue only arises if the relayer intentionally provides insufficient gas at any price. |
The recovery address is configured when the bridge transfer is initiated, if this or the executed calldata fails to be used correctly, I think the onus is on the sender. However, there are some legitimate concerns of a bridge relayer intentionally making the callback fail. Because funds aren't at direct risk, |
The recovery address only recover ERC20 tokens managed by the Connext bridge system. Other custom made bridging solution that utilize the arbitrary message passing never utilize that recovery address passed. ExampleFor example, if A lock "multiple BAYC NFT" on the Ethereum chain along with 1 WETH sent into Connext Amarok. On the destination chain, if executed calldata fails or gas limit is miscalculated (both intentionally and non-intentionally in case ether.js returns too low gas limit, it has happened many times on the complex contracts in 2021 not sure it is fixed or not), only 1 WETH is sent to the recovery address and not "multiple BAYC NFT". "Multiple BAYC NFT" will be locked on the Ethereum chain indefinitely without any chance to unlock or recovery it in the source chain. So, funds which are "multiple BAYC NFT" are at direct risk. BAYC floor price is currently more than 70 ETH. If 3 BAYC lost due to a single error, total 200+ ETH will be lost. Here is an example case that might become common if NFT is not out of hyped but sadly the hype in NFT is currently down. It is "NFT buying frontrunning" problem. Since Connext bridge requires 2-3 minutes between that times somebody may frontrun buying NFT without using bridge. Then the execution will be fail since NFT has been sold to buyer B. It only refund 10 ETH but not 3 NFT sent. Mitigration
Perfect mitigation is not found yet. There is an ongoing debate about this one at code-423n4/2022-07-axelar-findings#97 |
Fully agree with your take on this. But I still stand by my decision on keeping this as a The important thing is to not integrate with Connext with the guarantee that calldata will be successfully executed on the destination contract. This should be clearly documented and I think allowing the bridge user to re-execute calldata upon failure is a potentially useful suggestion, but this doesn't come with its pitfalls too. Added complexity could expand Connext's attack surface. |
In response to your proposed mitigation(s):
|
Lines of code
https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L113-L192
https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L194-L213
Vulnerability details
Impact
Current implementation of arbitrary call execute failure handler may break some use case for example NFT Bridge.
In the case of NFT Bridge, NFT may be lost forever.
This is likely to be happened in the case of out of gas.
Proof of Concept
Relayer receive the message to unlock BAYC on ETH chain. Relayer call execute on BridgeFacet which then call execute in Executor internally. Continue to these lines:
Unfortunately, an enormous NFT project has just started minting their NFT when the relayer perform the execution. Causing gas price to increase by 20x.
As a result, gasLimit is 20x lesser than what we have calculated causing ExcessivelySafeCall.excessivelySafeCall to fail because of out of gas. We fall into _handleFailure function. Notice that NFT is not unlocked yet because target contract has failed to being executed.
_handleFailure just sent dummy fund in the NFT bridge process to the useless fallback address (Useless in NFT bridge case as it doesn't involve any cross chain swapping / token transferring).
Finally, transferId will be marked as used (or reconciled). This transferId cannot be used anymore.
Recall that BAYC hasn't been unlocked yet as target contract has failed to being executed.
And we cannot reuse this transferId to retry anymore in the future as it is marked as used
As a result, BAYC is locked forever as target contract call never success anymore since transferId has been marked as used
Tools Used
Manual
Recommended Mitigation Steps
You should mix axelar style and connext style of error handling together.
Fund shouldn't be sent to fallback address immediately. Instead, leave an option for user to choose whether they want to recall the failed transaction manually or they want to transfer the fund to the fallback address.
The text was updated successfully, but these errors were encountered: