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: 13/47
Findings: 1
Award: $978.48
🌟 Selected for report: 0
🚀 Solo Findings: 0
978.4802 USDC - $978.48
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L58 https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L58 https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L123
The ASCII table contains letters, numbers, control characters, and other symbols. Each character is assigned a unique 7-bit code. ASCII is an acronym for American Standard Code for Information Interchange. The ASCII code for uppercase 'A' is 65 & 90 for 'Z'. The ASCII code for lowercase 'a' is 97 & 122 for 'z' which can be obtained by adding 32 to the the uppercase alphabets.
But in the given code, conversion of only A-F (65-70) to a-f(97-102) takes place instead of A-Z(65-90).
File: RemoteAddressValidator.sol function _lowerCase(string memory s) internal pure returns (string memory) { uint256 length = bytes(s).length; for (uint256 i; i < length; i++) { uint8 b = uint8(bytes(s)[i]); if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32)); /// @audit } return s; }
This would lead to incorrect validation when the corresponding hashes of the address are checked.
File: RemoteAddressValidator.sol function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool) { string memory sourceAddressLC = _lowerCase(sourceAddress); bytes32 sourceAddressHash = keccak256(bytes(sourceAddressLC)); if (sourceAddressHash == interchainTokenServiceAddressHash) { /// audit - incorrect check happens here return true; } return sourceAddressHash == remoteAddressHashes[sourceChain]; }
For example, if interchainTokenServiceAddressHash
is set in the constructor using all uppercase letters, the hash is calculated by only converting those alphabets whose value in the range 65-70.
File: RemoteAddressValidator.sol constructor(address _interchainTokenServiceAddress) { if (_interchainTokenServiceAddress == address(0)) revert ZeroAddress(); interchainTokenServiceAddress = _interchainTokenServiceAddress; interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString()))); }
And when the validateSender
is called using the address in all lowercase letters, a different hash would be generated thus reverting when calling the _execute
function which uses the onlyRemoteService
modifier.
File: InterchainTokenService.sol modifier onlyRemoteService(string calldata sourceChain, string calldata sourceAddress) { if (!remoteAddressValidator.validateSender(sourceChain, sourceAddress)) revert NotRemoteService(); _; }
A simple confusion of uppercase or lowercase & not converting the whole possible range can read to unnecessary reverts. Its better to convert the whole string to lowercase prevent ant possible bugs.
Manual Review
Use the whole range of ASCII value for the uppercase alphabets to prevent incorrect calculation of hashes.
- if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32)); + if ((b >= 65) && (b <= 90)) bytes(s)[i] = bytes1(b + uint8(32));
Invalid Validation
#0 - 0xSorryNotSorry
2023-07-27T20:38:59Z
The submission partly covers the primary issue.
#1 - c4-pre-sort
2023-07-27T20:39:03Z
0xSorryNotSorry marked the issue as low quality report
#2 - c4-pre-sort
2023-07-29T00:13:02Z
0xSorryNotSorry marked the issue as duplicate of #323
#3 - c4-judge
2023-09-08T11:55:34Z
berndartmueller marked the issue as satisfactory