xanoutas/solidity-security-findings huggingface dataset:
Message suspension removal disables proof verification 
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L82-L95
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L168-L206
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L229-L266


# Vulnerability details

## Impact
The ``Bridge`` contract enables suspension of transactions and removal of the suspension.
```solidity
    function suspendMessages(
        bytes32[] calldata _msgHashes,
        bool _suspend
    )
        external
        onlyFromOwnerOrNamed("bridge_watchdog")
    {
        uint64 _timestamp = _suspend ? type(uint64).max : uint64(block.timestamp);
        for (uint256 i; i < _msgHashes.length; ++i) {
            bytes32 msgHash = _msgHashes[i];
            proofReceipt[msgHash].receivedAt = _timestamp;
            emit MessageSuspended(msgHash, _suspend);
        }
    }

```

However the issue arises if the suspension is removed as it is enabled in the function.

1. A sender can process a ``recall()`` on the transaction after it is unsuspended. This is because the ``receivedAt`` variable is modified  directly when suspension is removed.
```solidity

        if (messageStatus[msgHash] != Status.NEW) revert B_STATUS_MISMATCH();

        uint64 receivedAt = proofReceipt[msgHash].receivedAt;
        bool isMessageProven = receivedAt != 0;
        

        if (!isMessageProven) {
        //    proof check happens here, but isMessageProven is true so proof is never checked
        }

        // The remaining actions are carried out successfully
                (uint256 invocationDelay,) = getInvocationDelays();

        if (block.timestamp >= invocationDelay + receivedAt) {
            delete proofReceipt[msgHash];
            messageStatus[msgHash] = Status.RECALLED;
```
2. In ``processMessage()``, proof verification is also skipped under the same conditions. 

```solidity
        if (messageStatus[msgHash] != Status.NEW) revert B_STATUS_MISMATCH();

        address signalService = resolve("signal_service", false);
        uint64 receivedAt = proofReceipt[msgHash].receivedAt;
        bool isMessageProven = receivedAt != 0;

        (uint256 invocationDelay, uint256 invocationExtraDelay) = getInvocationDelays();

        if (!isMessageProven) {
      //    proof check happens here, but isMessageProven is true so proof is never checked
        }

        // The remaining actions are carried out successfully
        if (invocationDelay != 0 && msg.sender != proofReceipt[msgHash].preferredExecutor) {
            // If msg.sender is not the one that proved the message, then there
            // is an extra delay.
            unchecked {
                invocationDelay += invocationExtraDelay;
            }
        }

        if (block.timestamp >= invocationDelay + recei
Messages in the 'retriable' status can't be suspended or banned
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/0xA5DF/taiko/blob/ade888fd023ea1c793cd5f0db7066d1ed2ab370c/packages/protocol/contracts/bridge/Bridge.sol#L310-L337


# Vulnerability details




## Impact
The bridge has the functionality to prevent an execution of a message by suspending it or prevent execution to a specific address by banning it.
However, this `retryMessage()` doesn't check that and will execute a message even if it's suspended or directed to a banned address.


## Proof of Concept
Consider the following scenario:
* The attacker sends a malicious message
* The bridge watchdog notices that and sends out a tx to suspend the message
* The attacker front-runs this tx, calling `processMessage()`, the message execution fails due to some kind of issue (e.g. out of gas), but the status has changed to 'retriable'
* Bridge watchdog tx to suspend the message is executed
* The attacker can now execute the message as long as they've managed to fix the issue (supplying more gas)


Add the following PoC to `test\bridge\Bridge.t.sol`, the test will pass:

<details>
<summary>Coded PoC</summary>

```solidity

    fallback() external payable{}

    function test_POC_SuspendRetriable() public {
        ControlledRevert dest = new ControlledRevert();

        IBridge.Message memory message = IBridge.Message({
            id: 0,
            from: address(bridge),
            srcChainId: uint64(block.chainid),
            destChainId: destChainId,
            srcOwner: Alice,
            destOwner: Alice,
            to: address(dest),
            refundTo: Alice,
            value: 1000,
            fee: 1000,
            gasLimit: 1_000_000,
            data: abi.encodeCall(GoodReceiver.onMessageInvocation, abi.encode(Carol)),
            memo: ""
        });
        // Mocking proof - but obviously it needs to be created in prod
        // corresponding to the message
        bytes memory proof = hex"00";

        bytes32 msgHash = destChainBridge.hashMessage(message);

        vm.chainId(destChainId);


        destChainBridge.processMessage(message, proof);


        address owner = destChainBridge.owner();


        bytes32[] memory msgsToSuspend = new bytes32[](3);
        msgsToSuspend[0] = msgHash;
        vm.prank(owner);

        destChainBridge.suspendMessages(msgsToSuspend, false);
        

        dest.setRevert(false);
        uint aliceBalanceBefore = Alice.balance;

        destChainBridge.retryMessage(message, false);

        IBridge.Status status = destChainBridge.messageStatus(msgHash);

        assertEq(status == IBridge.Status.DONE, true);


    }
```


</details>


## Recommended Mitigation Steps
Check if the message is suspended or if the dest address is banned when retrying a message


## Assessed type

Invalid Validation
Unauthorized entities can submit manipulated anchor transactions, disrupting L2 chain.
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L2/TaikoL2.sol#L107-L158


# Vulnerability details

The `anchor` function relies on the `GOLDEN_TOUCH_ADDRESS` to restrict access to the function. If the `GOLDEN_TOUCH_ADDRESS` is compromised or set incorrectly, unauthorized entities could potentially submit anchor transactions.
     - The function assumes that the `block.number` is incremented sequentially and uses it to calculate the `parentId`. If there are any gaps or inconsistencies in the block numbering, it could lead to incorrect calculations or exploits.
     - The function verifies the ancestor hashes and public input hashes, but there might be potential vulnerabilities if the hash calculation logic (`_calcPublicInputHash`) is flawed or can be manipulated.
     - The base fee per gas calculation (`_calc1559BaseFee`) is crucial for the correctness of the anchor transaction. Any vulnerabilities in this calculation could allow proposers to manipulate the base fee.

Snippet: https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L2/TaikoL2.sol#L107-L158

```solidity
     function anchor(
         bytes32 _l1BlockHash,
         bytes32 _l1StateRoot,
         uint64 _l1BlockId,
         uint32 _parentGasUsed
     )
         external
         nonReentrant
     {
         if (
             _l1BlockHash == 0 || _l1StateRoot == 0 || _l1BlockId == 0
                 || (block.number != 1 && _parentGasUsed == 0)
         ) {
             revert L2_INVALID_PARAM();
         }
     
         if (msg.sender != GOLDEN_TOUCH_ADDRESS) revert L2_INVALID_SENDER();
     
         uint256 parentId;
         unchecked {
             parentId = block.number - 1;
         }
     
         // Verify ancestor hashes
         (bytes32 publicInputHashOld, bytes32 publicInputHashNew) = _calcPublicInputHash(parentId);
         if (publicInputHash != publicInputHashOld) {
             revert L2_PUBLIC_INPUT_HASH_MISMATCH();
         }
     
         Config memory config = getConfig();
     
         // Verify the base fee per gas is correct
         uint256 basefee;
         (basefee, gasExcess) = _calc1559BaseFee(config, _l1BlockId, _parentGasUsed);
         if (!skipFeeCheck() && block.basefee != basefee) {
             revert L2_BASEFEE_MISMATCH();
         }
     
         if (_l1BlockId > lastSyncedBlock + BLOCK_SYNC_THRESHOLD) {
             ISignalService(resolve("signal_service", false)).syncChainData(
                 ownerChainId, LibSignals.STATE_ROOT, _l1BlockId, _l1StateRoot
             );
             lastSyncedBlock = _l1BlockId;
         }
     
         l2Hashes[parentId] = blockhash(parentId);
         publicInputHash = publicInputHashNew;
     
         emit Anchored(blockhash(parentId), gasExcess);
     }
```
The anchor transaction submission process is initiated by proposers who call the `anchor` funct
Lack of validation in proposeBlock fills ring buffer, halting block confirmation.
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L1/TaikoL1.sol#L55-L72
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L1/TaikoL1.sol#L67


# Vulnerability details

block proposal mechanism in the Taiko protocol, which allows proposers to submit new blocks to be added to the ring buffer for verification and confirmation.

Snippet: https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L1/TaikoL1.sol#L55-L72
```solidity
     function proposeBlock(bytes calldata _params, bytes calldata _txList)
         external
         payable
         nonReentrant
         whenNotPaused
         returns (TaikoData.BlockMetadata memory meta_, TaikoData.EthDeposit[] memory deposits_)
     {
         TaikoData.Config memory config = getConfig();
         (meta_, deposits_) = LibProposing.proposeBlock(state, config, this, _params, _txList);
         if (!state.slotB.provingPaused) {
             LibVerifying.verifyBlocks(state, config, this, config.maxBlocksToVerifyPerProposal);
         }
     }
```
The key steps involved in the block proposal function are:
     1. Get the current configuration settings.
     2. Call the `LibProposing.proposeBlock` function to propose a new block with the provided parameters and transaction list.
     3. If proving is not paused, call `LibVerifying.verifyBlocks` to verify the proposed block.

## Detail Description
The ring buffer has a fixed size, determined by the `blockRingBufferSize` parameter in the configuration.
   - If the ring buffer reaches its capacity with invalid blocks, it will prevent legitimate blocks from being proposed and processed.

The vulnerable [line#67](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L1/TaikoL1.sol#L67)
```solidity
     (meta_, deposits_) = LibProposing.proposeBlock(state, config, this, _params, _txList);
```
This line adds the proposed block to the ring buffer without sufficient validation, allowing invalid blocks to consume buffer space.

The block proposal function is expected to accept valid blocks from honest proposers and add them to the ring buffer for verification and confirmation.
   - The expected input values are the block parameters (`_params`) and the transaction list (`_txList`) associated with the proposed block.
   - The intended outcome is to have a balanced mix of valid blocks in the ring buffer, allowing for efficient block verification and confirmation.

> The ring buffer, having a fixed size, can be filled up with invalid blocks, leaving no space for legitimate blocks to be processed.
>  - As a result, the block confirmation process slows down or halts entirely, as valid blocks are unable to enter the ring buffer for verification.

## Impact
The system becomes unavailable or unresponsive
Lack of proper access control in onMessageRecalled allows token theft.
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/tokenvault/ERC20Vault.sol#L285-L313
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/tokenvault/ERC721Vault.sol#L110-L139


# Vulnerability details

`onMessageRecalled` function in both ERC20Vault and ERC721Vault contracts is responsible for handling the recall of messages and returning the tokens to the original sender.
   - The function takes two parameters:
     - `_message`: The recalled message containing information such as the sender, recipient, token, and amount.
     - `_msgHash`: The hash of the recalled message.
   - The function performs the following key steps:
     1. Verifies that the caller is the bridge contract through the `onlyFromBridge` modifier.
     2. Decodes the message data to extract the relevant information.
     3. Transfers the tokens back to the original sender.
     4. Emits a `TokenReleased` event to indicate the release of tokens.

## Detail Description
The function relies solely on the `onlyFromBridge` modifier to restrict access, assuming that only the bridge contract can call this function.
   - However, if an attacker manages to gain control of the bridge contract or if there is a vulnerability in the bridge contract itself, they could potentially exploit the `onMessageRecalled` function to recall messages and return tokens to arbitrary addresses.

Snippet: [ERC20Vault#onMessageRecalled](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/tokenvault/ERC20Vault.sol#L285-L313), [ERC721Vault#onMessageRecalled](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/tokenvault/ERC721Vault.sol#L110-L139)

```solidity
     function onMessageRecalled(
         IBridge.Message calldata _message,
         bytes32 _msgHash
     )
         external
         payable
         override
         nonReentrant
         whenNotPaused
     {
         // ...
         _message.srcOwner.sendEther(_message.value);
         // ...
     }
```
Under normal circumstances, the `onMessageRecalled` function is expected to be called only by the bridge contract when a message needs to be recalled.
   - The function should verify that the message recall is authentic and initiated by the original sender.
   - The tokens associated with the recalled message should be returned to the original sender.

> From the lack of proper access control, an attacker who gains control of the bridge contract or exploits a vulnerability in the bridge contract can manipulate the `onMessageRecalled` function.

> The attacker can construct a recalled message with arbitrary data, including a modified `srcOwner` address.

> By invoking the `onMessageRecalled` function with the manipulated message, the attacker can force the vault contract
Banned addresses can invoke/execute message call through retryMessage()
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L310


# Vulnerability details

## Impact
When an address is banned, `_message.data` will not be invoked by [_invokeMessageCall()](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L477) on the address. 

The issue is that if an address is banned while the message STATUS is RETRIABLE, the function [retryMessage()](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L310) does not stop the call from executing. This breaks the ban restriction on the address and allows `_message.data` to be invoked on it.

## Proof of Concept

1. Let's say the bridge_watchdog bans an address using function [banAddress()](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L101). 
 - On Line 113, it checks if the address is already banned. If not, set it to true on Line 114.
```solidity
File: Bridge.sol
105:     function banAddress(
106:         address _addr,
107:         bool _ban
108:     )
109:         external
110:         onlyFromOwnerOrNamed("bridge_watchdog")
111:         nonReentrant 
112:     {
113:         if (addressBanned[_addr] == _ban) revert B_INVALID_STATUS();
114:         addressBanned[_addr] = _ban;
115:         emit AddressBanned(_addr, _ban);
116:     }
```

2. In case of function [processMessage()](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L217), the banned address is refunded the Ether and its STATUS is set to DONE. This prevents the function [_invokeMessageCall()](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L477) from being called to execute the `_message.data` on the banned address.

```solidity
File: Bridge.sol
301:             // Process message differently based on the target address
302:             if (
303:                 _message.to == address(0) ||
304:                 _message.to == address(this) ||
305:                 _message.to == signalService ||
306:                 addressBanned[_message.to]
307:             ) {
308:                 // Handle special addresses that don't require actual invocation but
309:                 // mark message as DONE
310:                 refundAmount = _message.value;
311:                 _updateMessageStatus(msgHash, Status.DONE);
312:             } else {
```

3. But if the message is already in the RETRIABLE status when the address is banned, the function [retryMessage()](https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/bridge/Bridge.sol#L310) do
Repeated contesting of valid proofs in TaikoL1 slows block confirmation, potentially causing DoS.
Audit: 2024-03-taiko-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L1/TaikoL1.sol#L75-L94


# Vulnerability details

`proveBlock` function in the TaikoL1 contract allows users to submit proofs for block verification and enables other users to contest those proofs.
   - The function takes the following parameters:
     - `_blockId`: The ID of the block to be proven.
     - `_input`: The input data for the proof, including the block metadata, transition, and proof data.
   - The function performs the following key steps:
     1. Decodes the input data to extract the block metadata, transition, and proof.
     2. Verifies the validity of the block ID and checks if the block is within the valid range.
     3. Retrieves the block data from storage based on the block ID.
     4. Calls the `proveBlock` function from the LibProving library to process the proof.
     5. If the proof is valid, it updates the block's verification status and emits a `BlockVerified` event.

## Detail Description
The lack of proper restrictions on the contesting of proofs.
   - An attacker can repeatedly call the `proveBlock` function with the same valid proof, contesting it multiple times.
   - Each contest submission triggers the verification process, which consumes computational resources and delays the block confirmation.
   - By continuously contesting valid proofs, an attacker can significantly slow down or even stall the block confirmation process.

Snippet: https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/L1/TaikoL1.sol#L75-L94

```solidity
     function proveBlock(uint64 _blockId, bytes calldata _input) external {
         // ...
         uint8 maxBlocksToVerify = LibProving.proveBlock(state, config, this, meta, tran, proof);
         // ...
     }
```
Under normal circumstances, the `proveBlock` function is expected to allow users to submit proofs for block verification and enable legitimate contesting of proofs.
   - The function should process valid proofs efficiently and confirm blocks in a timely manner.
   - The input values should include the block ID, block metadata, transition, and proof data.

The problem is, an attacker can exploit the `proveBlock` function by repeatedly contesting valid proofs.
   - The repeated contests consume computational resources and delay the block confirmation process.
   - As a result, the function's behavior deviates from the expected outcome, leading to prolonged block confirmation times and potential DoS conditions.

## Impact
The repeated contesting of valid proofs can significantly slow down the block confirmation process, leading to slower transaction processing and reduced system throughput.

If an attacker can contest proofs faster than they can be processed, it can potentially lead to a DoS condition, rendering the system unusable.

## Proof of Concept
1. An attacker identifies a valid p