MorpheusAI

MorpheusAI
Foundry
22,500 USDC
View results
Submission Details
Severity: medium
Invalid

`L2MessageReceiver` contract: changing `config.sender` address will result in stuck minting messages

Summary

L2MessageReceiver contract: changing config.sender address will result in stuck minting messages.

Vulnerability Details

  • The L1Sender contract is responsible of managing and redirecting calls from L1 to L2 gateways.

  • The Distribution contract will call the L1Sender contract when the stakers of pools claim their rewards via Distribution.claim function, where a mint message is going to be sent to the L2MessageReceiver contract on Arbitrum chain, and this operation is done via the layer zero endpoint on the Ethereum chain (via send function implemented by the layer zero endpoint):

    //@@notice : from L1Sender.sendMintMessage function
    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")
    );
  • The mint message is going to be received and executed by the L2MessageReceiver contract on Arbitrum; where it will check if the sender of the lz message is the authorized L1Sender contract address before minting the MOR tokens to the claimer address:

    //@@notice : from L2MessageReceiver._nonblockingLzReceive function
    assembly {
    sender_ := mload(add(senderAndReceiverAddresses_, 20))
    }
    require(sender_ == config.sender, "L2MR: invalid sender address");
  • So as can be noticed: the config.receiver in L1Sender contract should be the config.sender in the L2MessageReceiver contract as the L2MessageReceiver._nonblockingLzReceive function will extract the first encoded address from the senderAndReceiverAddresses_ argument.

  • Knowing that the L2MessageReceiver implements a non-blocking receive mechanism, where any failed mint messages are catched and saved in the L2MessageReceiver contract so that they can be executed later:
    if the admin of the L2MessageReceiver contract changes the config.sender address; this will result in failed messages to never be executed as the aforementioned check on the sender address will revert.

Impact

This will result in users losing their entitled rewards, as the Distribution contract will reset their uncalimed rewards to zero when they claim them, optimistically assuming that their rewards will be successfully minted on L2, and the L2MessageReceiver will never be able to execute their failed rewards minting.

Proof of Concept

L1Sender.sendMintMessage function/ L127-L137

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")
);

L2MessageReceiver._nonblockingLzReceive function/ L97-L101

address sender_;
assembly {
sender_ := mload(add(senderAndReceiverAddresses_, 20))
}
require(sender_ == config.sender, "L2MR: invalid sender address");

L2MessageReceiver.setParams function

function setParams(address rewardToken_, Config calldata config_) external onlyOwner {
rewardToken = rewardToken_;
config = config_;
}

Tools Used

Manual Review.

Recommendations

In L2MessageReceiver contract : add a mechanism to cache the config.sender address for the failed messages so that they can be executed later even if the config.sender address is changed.

Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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