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

3 stars 2 forks source link

Loops in bridging process disrupt transactions, potentially leading to denial of service. #140

Open c4-bot-9 opened 3 months ago

c4-bot-9 commented 3 months ago

Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/signal/SignalService.sol#L83-L134 https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/signal/SignalService.sol#L104-L129

Vulnerability details

Description

proveSignalReceived function in the SignalService contract is responsible for verifying the receipt of signals across multiple hops in the bridging process.

The problem is users can create a hopProofs array that contains a loop, where one or more hops point back to a previous hop, creating a circular dependency. When the function processes the malicious hopProofs array, it enters an infinite loop or exhibits unexpected behavior, such as:

  • The loop can cause the function to consume all available gas, leading to a transaction failure and potentially disrupting the normal operation of the protocol.
  • If the loop affects the token transfers or state updates, it can enable malicious actors to steal tokens by repeatedly executing the same hop and manipulating the token balances.
  • The presence of loops can disrupt the normal functioning of the multi-hop bridging process, effectively causing a denial of service for legitimate users.

Impact

The presence of loops can disrupt the normal functioning of the multi-hop bridging process, preventing legitimate users from successfully completing their bridging transactions.

Tools Used

Manual Review

Recommended Mitigation Steps

function proveSignalReceived(
    uint64 _chainId,
    address _app,
    bytes32 _signal,
    bytes calldata _proof
)
    public
    virtual
    validSender(_app)
    nonZeroValue(_signal)
{
    HopProof[] memory hopProofs = abi.decode(_proof, (HopProof[]));
    if (hopProofs.length == 0) revert SS_EMPTY_PROOF();

    uint64 chainId = _chainId;
    address app = _app;
    bytes32 signal = _signal;
    bytes32 value = _signal;
    address signalService = resolve(chainId, "signal_service", false);

+   mapping(uint64 => mapping(address => bool)) visited;

    HopProof memory hop;
    for (uint256 i; i < hopProofs.length; ++i) {
        hop = hopProofs[i];

        // Loop detection
+       if (visited[hop.chainId][app]) revert SS_LOOP_DETECTED();
+       visited[hop.chainId][app] = true;

        // ...

        chainId = hop.chainId;
        app = signalService;
    }

    // ...
}

Assessed type

Loop

c4-pre-sort commented 3 months ago

minhquanym marked the issue as duplicate of #125

c4-judge commented 3 months ago

0xean marked the issue as satisfactory

c4-judge commented 3 months ago

0xean changed the severity to QA (Quality Assurance)

c4-judge commented 3 months ago

0xean marked the issue as grade-b