MorpheusAI

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

A malicious user can grief any users claim causing them to lose their staking reward tokens (MOR)

Summary

A malicious user can grief any users claim causing them to lose their staking reward tokens (MOR)

Vulnerability Detail

Any user can call claim for another user, that user must pay for the layerzero fee though. The problem arises when the malicious user calls claim with a contract on the L1 and deploys a contract to the L2 alias which is not payable. Because in the claim function we set the refundee to _msgSender() the refundee will be the callers address on the L2 which will be nonpayable.

L1Sender(l1Sender).sendMintMessage{value: msg.value}(user_, pendingRewards_, _msgSender());

we can observe how we set msgsender to refundee of the call to sendMintMessage.

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

Above we see that the call to sendMintMessage with the msgsender as the refundTo parameter. And the refundTo parameter is then passed to the send call to layerZero. When layerZero attempts to send the refunded eth to the refundTo address on the L2, the entire tx will revert with the error

LayerZero: failed to refund
The specified _refundAddress is not payable, or invalid. (Try sending the exact amount)

This will cause the layerzero call on the L2 to revert. And since this call is what is used to mint the MOR tokens to the user on the L2 (arbitrum), the user will essentially never get his MOR tokens minted to him. In the L1 when we called claim, we also set the users pending rewards to 0. Essentially, the users rewards are lost forever. Below we observe the setting of pending rewards to 0 in the claim function line 170

userData.rate = currentPoolRate_;
userData.pendingRewards = 0;

This can be done for everyone who has pending rewards.

POC

  1. malicious user creates contract on L1 that can call claim

  2. malicious user creates contract on L2 with the same adress but this contract will be non payable

  3. malicious user call claim for another user using his contract in L1

  4. refundTo is set to the contracts address.

  5. When on layer2 when layerzero attempts to refund the ETH, it will be hit with a revert, failed to refund

  6. On L2 the users pending rewards were set to 0, but the users never received his rewards because the tx reverts

Impact

A user can grief all users rewards in the protocol, causing them to lose all of their pending rewards.

Code Snippet

https://github.com/Cyfrin/2024-01-Morpheus/blob/07c900d22073911afa23b7fa69a4249ab5b713c8/contracts/Distribution.sol#L154-L177

Tool used

Manual Review

Recommendation

Do not allow anyone to call claim to claim rewards for other users.

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.