MorpheusAI

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

User could lost opportunity retry mint, if owner has change config

Summary

When user call retry() function, contract check again params, such chain id and sender id. it could cause revert again.

Vulnerability Details

When Tx has revert on L2 in L2MessageReceiver contract, payload will be stored in failedMessages mapping. Also stored sender nonce, chainID and senderAndReceiverAddresses_ variable.

try
IL2MessageReceiver(address(this)).nonblockingLzReceive(
senderChainId_,
senderAndReceiverAddresses_,
payload_
)
{
emit MessageSuccess(senderChainId_, senderAndReceiverAddresses_, nonce_, payload_);
} catch (bytes memory reason_) {
failedMessages[senderChainId_][senderAndReceiverAddresses_][nonce_] = keccak256(payload_);

When user want to try again execute tx, he call retryMessage() function, which call internal function _nonblockingLzReceive.
IF owner has change config, using function setParams() in period between after user'stx fail and before user call retryMessage(), user could not execute tx, even if the cause of the previous reversal has been eliminated, because the _nonblockingLzReceive function again compares the chain ID and sender of the message from values from mapping with the current config values. These values will naturally not match, because the owner has changed some parameters in the config. And the transaction will reverse again.

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

Owner may change the config due to security or other reasons. it is for these purposes that there is an external function setParams()

Example:
If on L2 MOR token's CAP is 1000. And was already minted 950. Our user have reward as 60 tokens.
User call claim(). Contract make call to LZ.
Contract L2MessageReceiver receive message and call internal function _blockingLzReceive, which contain try/catch block.
In try/catch block tx fail, because new supply of tokens will be greater, than CAP value. So payload will be stored in mapping failedMessages

} catch (bytes memory reason_) {
failedMessages[senderChainId_][senderAndReceiverAddresses_][nonce_] = keccak256(payload_);
emit MessageFailed(senderChainId_, senderAndReceiverAddresses_, nonce_, payload_, reason_);
}

After some times, owner change config (for example sender's address).
Other user burn some MOR tokens, so our user could mint again his 60 tokens and it will be less than CAP value.
Our user call retryMessage() -> _nonblockingLzReceive. And it will revert, because stored sender's address from failedMessages mapping is different from current value from config - config.sender.

Impact

User could not call retry function, so he lost opportunity to mint his MOR tokens.

Tools Used

Manual review

Recommendations

Change the code so that when the _nonblockingLzReceive function is called from the retryMessage function, it does not check the chainid and the sender's address with current config values, because it will be already validated at first call (when tx has revert).

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
sovaslava Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
sovaslava Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
sovaslava Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
sovaslava Submitter
over 1 year ago
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.