MorpheusAI

MorpheusAI
Foundry
22,500 USDC
View results
Submission Details
Severity: low
Valid

Insufficient Gas Fee Validation in Cross-Layer Communication Vulnerability

Summary

The L2TokenReceiver contract's sendMintMessage() function does not adequaly validates gas fees for LayerZero endpoint communication. This lack of validation poses risks of failed or stuck transactions and potential exploitation through repeated low-gas submissions.

Vulnerability Details

As you can see below you can send any amount of gas through msg.value in Distribution.sol#claim() function.
But if no minimum gas is enforced, an application that has the intention of using the NonBlockingApp can end up in a situation where there is a StoredPayload and the pathway is blocked.

The blocking communication pathway issue in sendMintMessage() can be understood in the context of the ILayerZeroEndpoint(config.gateway).send function call:

// Distribution.sol :

function claim(uint256 poolId_, address user_) external payable poolExists(poolId_) {
//// ... ////
// Transfer rewards @audit claimer control msg.value
L1Sender(l1Sender).sendMintMessage{value: msg.value}(user_, pendingRewards_, _msgSender());
emit UserClaimed(poolId_, user_, pendingRewards_);
}

// L1Sender.sol :

function sendMintMessage(address user_, uint256 amount_, address refundTo_) external payable onlyDistribution {
RewardTokenConfig storage config = rewardTokenConfig;
bytes memory receiverAndSenderAddresses_ = abi.encodePacked(config.receiver, address(this));
bytes memory payload_ = abi.encode(user_, amount_);
ILayerZeroEndpoint(config.gateway).send{value: msg.value}(
config.receiverChainId, // communicator LayerZero chainId
receiverAndSenderAddresses_, // send to this address to the communicator
payload_, // bytes payload
payable(refundTo_), // refund address
address(0x0), // future parameter
bytes("") // adapterParams (see "Advanced Features")
);
}

In this code:

  • ILayerZeroEndpoint(config.gateway).send is used to send a message across LayerZero.

  • adapterParams is passed as an empty byte array (bytes("")), indicating no specific parameters for the message, including gas limits.

Attack scenario :

  • The attacker calls claim() and specifies a small amount of gas as msg.value. The Relayer delivers the transaction with the specified gas at the destination.

  • The transaction is first validated through the LayerZero contracts before it reaches the lzReceive function. The Relayer will give exactly the gas which was specified through the claim() function. The line where it happens inside the LayerZero contract is here, and {gas: _gasLimit} is the gas the sender has paid for. The objective is that due to this small gas passed the transaction reverts somewhere inside the lzReceive function and the message pathway is blocked, resulting in StoredPayload.

Impact

In the Morpheus AI protocol, this could be exploited to frequently block communication pathways between chains by sending messages with insufficient gas, causing them to revert and thus disrupt the service.
Or a loss of funds for users that does not send enough gas through claiming process

Tools Used

VSCode
Solodit 1
Solodit 2

Recommendations

Estimate gas fees using layerZero documentation and require user to send at least estimated fees

Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

LayerZero Integration: `sendMintMessage` doesn't verify the `msg.value` sent by the user facilitating failed transactions.

Support

FAQs

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