Platform: Code4rena
Start Date: 12/07/2023
Pot Size: $80,000 USDC
Total HM: 11
Participants: 47
Period: 9 days
Judge: berndartmueller
Total Solo HM: 1
Id: 260
League: ETH
Rank: 12/47
Findings: 2
Award: $1,073.25
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Jeiwan
Also found by: 0xkazim, Emmanuel, KrisApostolov, T1MOH, Toshii, UniversalCrypto, Viktor_Cortess, immeas, libratus, nobody2018, qpzm
94.7708 USDC - $94.77
Cross-chain proposals can have value attached to them, however neither InterchainProposalExecutor
or AxelarExecutable
(which exposes the execute
function) can receive either.
However _executeProposal
tries to send value without having any way to receive any ether
(bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData);
Here you can see _executeProposal
makes a call which intends to send ether
function _executeProposal(InterchainCalls.Call[] memory calls) internal { // @audit-issue AxelarExecutable isn't payable for (uint256 i = 0; i < calls.length; i++) { InterchainCalls.Call memory call = calls[i]; (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData); if (!success) { _onTargetExecutionFailed(call, result); } else { _onTargetExecuted(call, result); } } }
This is called from _execute which isn't payable.
Neither is AxelarExecutable - execute
Neither AxelarExecutable
nor InterchainProposalExecutor
contain or inherit a receive
or fallback payable
to receive ether
manual
Make AxelarExecutable - execute
payable or implement a receive
function to allow the call in _executeProposal
to send ether
Payable
#0 - c4-pre-sort
2023-07-29T00:04:20Z
0xSorryNotSorry marked the issue as duplicate of #319
#1 - c4-judge
2023-09-08T10:59:23Z
berndartmueller marked the issue as satisfactory
#2 - c4-judge
2023-09-08T10:59:33Z
berndartmueller changed the severity to 2 (Med Risk)
🌟 Selected for report: T1MOH
Also found by: Chom, UniversalCrypto
978.4802 USDC - $978.48
InterchainProposalExecutor
uses _execute
for incoming cross-chain proposals. This function uses a custom library to convert the incoming string calldata sourceAddress
to an address
using toAddress
. However toAddress
assumes the incoming string is formatted like an EVM address and will revert if this is not the case, meaning the incoming proposal will fail.
function toAddress(string memory addressString) internal pure returns (address) { bytes memory stringBytes = bytes(addressString); uint160 addressNumber = 0; uint8 stringByte; if (stringBytes.length != 42 || stringBytes[0] != '0' || stringBytes[1] != 'x') revert InvalidAddressString(); for (uint256 i = 2; i < 42; ++i) { stringByte = uint8(stringBytes[i]); if ((stringByte >= 97) && (stringByte <= 102)) stringByte -= 87; else if ((stringByte >= 65) && (stringByte <= 70)) stringByte -= 55; else if ((stringByte >= 48) && (stringByte <= 57)) stringByte -= 48; else revert InvalidAddressString(); addressNumber |= uint160(uint256(stringByte) << ((41 - i) << 2)); } return address(addressNumber); }
Here you can see if the incoming addressString
doesn't start with 0x
or isn't of the correct length the call will revert.
Manual
Ensure all incoming addresses from non-evm chains are dispatched in the correct format to be received
DoS
#0 - c4-pre-sort
2023-07-29T00:13:12Z
0xSorryNotSorry marked the issue as duplicate of #323
#1 - c4-judge
2023-09-01T12:06:01Z
berndartmueller marked the issue as not a duplicate
#2 - c4-judge
2023-09-01T12:06:28Z
berndartmueller marked the issue as primary issue
#3 - c4-judge
2023-09-05T09:21:38Z
berndartmueller marked the issue as duplicate of #25
#4 - c4-judge
2023-09-05T09:22:01Z
berndartmueller marked the issue as satisfactory