TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: low
Invalid

Channel Blocking Exploit Due to No Non-Blocking Implementation

Summary

Failure to follow the non-blocking standard recommended by LayerZero can result in blocking the channel between the source and destination applications. This can disrupt the normal flow of transactions and lead to potential denial-of-service scenarios.

Vulnerability Details

According to the LayerZero documentation, the default behavior when a transaction on the destination application fails is that the channel between the source and destination applications gets blocked. Before any new transactions can be executed, the failed transaction must be retried until it succeeds . This behavior can be exploited by an attacker to initiate a transaction they know will fail, effectively blocking the channel.

The proof of concept is that the TempleGold.sol contract does not implement the non-blocking approach, as seen in the following code snippet:

function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address /*_executor*/, // @dev unused in the default implementation.
bytes calldata /*_extraData*/ // @dev unused in the default implementation.
) internal virtual override {
// @dev The src sending chain doesn't know the address length on this chain (potentially non-evm)
// Thus everything is bytes32() encoded in flight.
address toAddress = _message.sendTo().bytes32ToAddress();
// @dev Credit the amountLD to the recipient and return the ACTUAL amount the recipient received in local decimals
uint256 amountReceivedLD = _credit(toAddress, _toLD(_message.amountSD()), _origin.srcEid);
/// @dev Disallow further execution on destination by ignoring composed message
if (_message.isComposed()) { revert CannotCompose(); }
emit OFTReceived(_guid, _origin.srcEid, toAddress, amountReceivedLD);
}

The _lzReceive function, which mints the tokens on the destination chain in the TempleTelporter.sol, is defined as:

Copy code
function _lzReceive(
Origin calldata /*_origin*/,
bytes32 /*_guid*/,
bytes calldata _payload,
address /*_executor*/,
bytes calldata /*_extraData */
) internal override {
// Decode the payload to get the message
(address _recipient, uint256 _amount) = abi.decode(_payload, (address, uint256));
temple.mint(_recipient, _amount);
}

Impact

This implementation does not adhere to the non-blocking standard recommended by LayerZero. If the _lzReceive function fails, it can block the channel between the source and destination applications, preventing any new transactions from being executed until the failed transaction is retried and succeeds.

Tools Used

  • Code editor/IDE

  • LayerZero documentation and code examples

Recommendations

Implement the non-blocking approach recommended by LayerZero to prevent the channel from being blocked. An example implementation can be found in LayerZero's NonblockingLzApp.sol:

function _nonblockingLzReceive(
uint16 _srcChainId,
bytes memory _srcAddress,
uint64 _nonce,
bytes memory _payload
) internal virtual {
// Handle the message
}
function _lzReceive(
uint16 _srcChainId,
bytes memory _srcAddress,
uint64 _nonce,
bytes memory _payload
) internal virtual override {
// Try-catch to ensure the transaction does not revert
try this.nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload) {
// No-op
} catch {
// Handle failure
}
}
}

Modify all the lzRecieve functions to follow a similar pattern, ensuring that the communication channel remains open even if a transaction fails.

References:

  1. LayerZero Messaging Properties

  2. LayerZero Non-Blocking LzApp Guide

  3. LayerZero NonblockingLzApp.sol Example

Updates

Lead Judging Commences

inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Not using the Non-Blocking Implementation might get the teleporter stuck

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.