The IsSendEnabledCoins function is responsible for ensuring coins with SendEnabled as false cannot be sent via MsgSend and MsgMultiSend. These are also enforced when creating vesting accounts to prevent users from transferring send-disabled coins to a recipient.
However, it is not enforced within the SendCoinsFromModuleToAccount, SendCoinsFromModuleToModule, and SendCoinsFromAccountToModule functions.
This may allow a user to transfer send-disabled coins via the following scenario:
SendCoinsFromModuleToAccount.SendCoinsFromModuleToModule.SendCoinsFromAccountToModule.SendEnabled is false) to Bob.MsgCreateValidator with msg.Commission.Rate to be 100%.MsgDepositValidatorRewardsPool with msg.ValidatorAddress as Bob’s address and msg.Amount as the send-disabled coin.
distribution module via the SendCoinsFromAccountToModule function.AllocateTokensToValidator function. Since the commission is set to 100% in step 2, Bob will receive all the tokens and update via the SetValidatorAccumulatedCommission function.MsgWithdrawValidatorCommission to transfer the send-disabled coin from the distribution module to their address via the SendCoinsFromModuleToAccount function.
MsgSetWithdrawAddress to set their withdrawal address to Carol’s address.
GetDelegatorWithdrawAddr.IsSendEnabledCoins validation can be bypassed. With the above steps, an attacker can send the send-disabled coins to themselves or other recipients.Here is another instance that allows sending send-disabled coins:
MsgFundCommunityPool to fund the community pool with the send-disabled coin.
distribution module via the SendCoinsFromAccountToModule function.MsgCommunityPoolSpend via the SendCoinsFromModuleToAccount function.Consider implementing the IsSendEnabledCoins validation in the SendCoinsFromModuleToAccount function.