MorpheusAI

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

Reentrancy when retrying failed messages can lead to excess minting of `MOR` tokens

Summary

When a transaction fails, the transaction can be retried to clear up the message queue. Doing this requires anyone to call the retryMessage function so as to free up the queue. The function however, doesn't follow CEI, making it vulnerable to a reentrancy, from which a malicious users can excessively mint MOR tokens.

Vulnerability Details

To free up the message queue, the user calls the retryMessage function. Note the function arrangement.

function retryMessage(
uint16 senderChainId_,
bytes memory senderAndReceiverAddresses_,
uint64 nonce_,
bytes memory payload_
) external {
bytes32 payloadHash_ = failedMessages[senderChainId_][senderAndReceiverAddresses_][nonce_];
require(payloadHash_ != bytes32(0), "L2MR: no stored message"); //@note checks
require(keccak256(payload_) == payloadHash_, "L2MR: invalid payload"); //@note checks
_nonblockingLzReceive(senderChainId_, senderAndReceiverAddresses_, payload_); //@note interaction
delete failedMessages[senderChainId_][senderAndReceiverAddresses_][nonce_]; //@note effect
emit RetryMessageSuccess(senderChainId_, senderAndReceiverAddresses_, nonce_, payload_);
}

The function performs the required checks, then calls the _nonblockingLzReceive function, upon which MOR tokens are minted to the user through the external mint function in the MOR.sol contract.

function _nonblockingLzReceive(
uint16 senderChainId_,
bytes memory senderAndReceiverAddresses_,
bytes memory payload_
) private {
require(senderChainId_ == config.senderChainId, "L2MR: invalid sender chain ID");
address sender_;
assembly {
sender_ := mload(add(senderAndReceiverAddresses_, 20))
}
require(sender_ == config.sender, "L2MR: invalid sender address");
(address user_, uint256 amount_) = abi.decode(payload_, (address, uint256));
IMOR(rewardToken).mint(user_, amount_); //@note
}

By creating a contract that can repeatedly call the retryMessage function, the MOR tokens can be repeatedly minted, before the failedMessage's params are deleted.

Impact

Excessive minting of MOR tokens.

Tools Used

Manual Code Review

Recommendations

Follow the CEI pattern or add a reentrancy guard.
Note that the original implementation of the retryMessge function also deletes the failed messages before making the call to the _nonblockingLzReceive function.

Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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