code-423n4 / 2024-03-taiko-findings

3 stars 2 forks source link

Invalid Signal used to Prove Signal Received #211

Closed c4-bot-5 closed 7 months ago

c4-bot-5 commented 7 months ago

Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/main/packages/protocol/contracts/bridge/Bridge.sol#L384 https://github.com/code-423n4/2024-03-taiko/blob/main/packages/protocol/contracts/bridge/Bridge.sol#L364 https://github.com/code-423n4/2024-03-taiko/blob/main/packages/protocol/contracts/bridge/Bridge.sol#L579

Vulnerability details

Impact

Invalid Signal used to Prove Signal Received in the Bridge contract

Proof of Concept

    function _proveSignalReceived(
        address _signalService,
 >>>       bytes32 _signal,
        uint64 _chainId,
        bytes calldata _proof
    )
        private
        view
        returns (bool success_)
    {
        bytes memory data = abi.encodeCall(
            ISignalService.proveSignalReceived,
            (_chainId, resolve(_chainId, "bridge", false), _signal, _proof)
        );
        (success_,) = _signalService.staticcall(data);
    }

The function above shows how Received signals are proven by the _proveSignalReceived(...) function, it can be noted that the second parameter takes in the signal to be proven. A look at the code below also shows where this function is called as noted in the pointer, it can be noted that the hashed Message was converted to signal before it was proved with the _proveSignalReceived(...) function.

    function proveMessageFailed(
        Message calldata _message,
        bytes calldata _proof
    )
        public
        view
        returns (bool)
    {
        if (_message.srcChainId != block.chainid) return false;

        return _proveSignalReceived(
            resolve("signal_service", false),
>>>            signalForFailedMessage(hashMessage(_message)),
            _message.destChainId,
            _proof
        );
    }

The problem is in the code below in other instance where this signal prove function was called, instead of converting the hashMessage to a provable signal, the hash message was used directly which would means proving an invalid signal

 function proveMessageReceived(
        Message calldata _message,
        bytes calldata _proof
    )
        public
        view
        returns (bool)
    {
        if (_message.destChainId != block.chainid) return false;
        return _proveSignalReceived(
>>>            resolve("signal_service", false), hashMessage(_message), _message.srcChainId, _proof
        );
    }

Tools Used

Manual Reveiw

Recommended Mitigation Steps

The protocol should make necessary adjustment to ensure the hashMessage is first converted to a provable signal to avoid Denial of service or loss of fund from Wrong Signal

Assessed type

en/de-code

c4-pre-sort commented 7 months ago

minhquanym marked the issue as insufficient quality report

minhquanym commented 7 months ago

Insufficient proof

c4-sponsor commented 7 months ago

dantaik (sponsor) disputed

c4-judge commented 7 months ago

0xean marked the issue as unsatisfactory: Insufficient proof