Light ModeLight
Light ModeDark

One Bug Per Day

One H/M every day from top Wardens

Checkmark

Join over 1130 wardens!

Checkmark

Receive the email at any hour!

Ad

All bridged funds will be lost for the users using the account abstraction wallet

mediumCode4rena

Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/SourceBridge.sol#L61-L82 https://github.com/code-423n4/2023-09-ondo/blob/47d34d6d4a5303af5f46e907ac2292e6a7745f6c/contracts/bridge/DestinationBridge.sol#L85-L114

Vulnerability details

Impact

Users with account abstraction wallets have different address across different chains for same account, so if someone using account abstraction wallet bridge the asset, assets will be minted to wrong address and lost permanently

Proof of Concept

Account abstraction wallet have been on the rise for quite a time now and have alot of users, just look at the figures by safe wallet (one of the account abstraction wallet) image

4.4 million users and 5.4 billion assets, there is very high risk that safe wallet users will try to bridge the assets and lost them.

Now look at the codebase and understand how the assets will be lost.

In source bridge in burnAndCallAxelar we construct the payload as follow :

here we can see the payload passes msg.sender as receiving address on other chain assuming that user have same address across all the evm chains, which is not the case if user is using the account abstraction wallet

solidity
bytes memory payload = abi.encode(VERSION, msg.sender, amount, nonce++);

and than call the following function passing the payload, which calls the callContract function passing the payload to axelar network

solidity
function _payGasAndCallCotract( string calldata destinationChain, string memory destContract, bytes memory payload ) private { GAS_RECEIVER.payNativeGasForContractCall{value: msg.value}( address(this), destinationChain, destContract, payload, msg.sender ); // Send all information to AxelarGateway contract. AXELAR_GATEWAY.callContract(destinationChain, destContract, payload); }

Than on the destination any axelar node will call the excute() function passing in the payload and the tokens will be minted to account abstraction wallet address of the source chain but on destination same person will not be the owner of that address, and hence tokens are permanently lost

solidity
function _execute( string calldata srcChain, string calldata srcAddr, bytes calldata payload ) internal override whenNotPaused { (bytes32 version, address srcSender, uint256 amt, uint256 nonce) = abi .decode(payload, (bytes32, address, uint256, uint256)); if (version != VERSION) { revert InvalidVersion(); } if (chainToApprovedSender[srcChain] == bytes32(0)) { revert ChainNotSupported(); } // each chain have only on approved sender that is the source bridge contract. if (chainToApprovedSender[srcChain] != keccak256(abi.encode(srcAddr))) { revert SourceNotSupported(); } if (isSpentNonce[chainToApprovedSender[srcChain]][nonce]) { revert NonceSpent(); } isSpentNonce[chainToApprovedSender[srcChain]][nonce] = true; // same payload would have the same txhash bytes32 txnHash = keccak256(payload); txnHashToTransaction[txnHash] = Transaction(srcSender, amt); _attachThreshold(amt, txnHash, srcChain); _approve(txnHash); _mintIfThresholdMet(txnHash); emit MessageReceived(srcChain, srcSender, amt, nonce); }

Tools Used

Manual reviewing with some googling on different addresses across chains and have also read already somewhere in some contest, just could not find that report now.

Recommended Mitigation Steps

Give the user to pass in the address the tokens should be minted to on the destination bridge. And pass in the warning for account abstraction wallet holders to not to pass the same wallet. Some wallets may follow the deterministic deployment approach to have same address, but as safe explains that grantees nothing as each chain have its own different state and opcode differences so even deterministic approach may generate different addresses.

Assessed type

Invalid Validation