MorpheusAI

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

All claimed rewards will be lost for the users using the account abstraction wallet

Summary

Users with account abstraction wallets have different addresses across different chains for the same account, so if all rewards are claimed for someone using an account abstraction wallet, the rewards will be minted to the wrong address and lost permanently. Also, a malicious attacker/attackers who notices this could perform griefing attacks on all account abstraction wallet users by voluntarily executing claim() for all these users.

Vulnerability Details

With 5.7 million users and 79 billion assets, there is a very high risk that the claim rewards will be called on safe wallet users and lose all the rewards.

Now, look at the codebase and understand how all the rewards will be lost for the users.

In the Distribution.sol::claim() we call the l1sender to send the mint rewards message as follows:

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

Here, we can see the function passes the exact address of the user: user_ as the receiving address on the other chain, assuming that the user has the same address across all the EVM chains; which is not the case if the user is using the account abstraction wallet.

Then, on the l1Sender contract it calls the function sendMintMessage() receiving the user_ as the payload, which then calls the LayerZeroEndpoint send function passing the payload to LayerZeroEndpoint.

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

Then, on the l2, lzReceive function will be triggered, which will in turn call _nonblockingLzReceive() passing in the payload. The rewards will be minted to the l1 chain's account abstraction wallet address, but on l2 chain, the same person will not be the owner of that address; hence, all rewards are permanently lost. Also, a malicious attacker/attackers who notices this could perform griefing attacks on all account abstraction wallet users by voluntarily executing claim() for all these users.

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

Impact

If all rewards are claimed for someone using an account abstraction wallet, the rewards will be minted to the wrong address and lost permanently.

Recommendations

Give the user the option to pass in the address the rewards should be minted to on the l2 by adding an extra address variable to the userdata struct which should be set only by the user.

struct UserData {
uint128 lastStake;
uint256 deposited;
uint256 rate;
uint256 pendingRewards;
+ address l2recipient;
}

Pass in the warning for account abstraction wallet holders to not to pass the same wallet.

Updates

Lead Judging Commences

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

Users that interact through smart contracts, account abstaction or multisig wallets lose all rewards because they are not the owners of the same addresses on L2

Support

FAQs

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