- 
                Notifications
    You must be signed in to change notification settings 
- Fork 0
Open
Description
Micro Neon Beaver
Medium
Blacklisted Users Can Receive mTokens Through Mint-on-Behalf
Summary
The blacklist check in beforeMTokenMint only validates the minter, not the receiver, allowing blacklisted users to receive mTokens through third-party minting
Root Cause
In src/Operator/Operator.sol:589, the beforeMTokenMint() function only checks ifNotBlacklisted(minter), but the actual mToken recipient is the receiver parameter passed to __mint() at src/mToken/mToken.sol:716.
Operator.sol - Only checks minter:
function beforeMTokenMint(address mToken, address minter)
    external view override 
    onlyAllowedUser(minter) 
    ifNotBlacklisted(minter)  // BUG: Doesn't check receiver
{
    // ...
}mToken.sol - Receiver gets the tokens:
function __mint(address minter, address receiver, uint256 mintAmount, ...) {
    IOperatorDefender(operator).beforeMTokenMint(address(this), minter);
    // ...
    
    // RECEIVER gets the mTokens, not minter
    accountTokens[receiver] = accountTokens[receiver] + mintTokens;
    emit Transfer(address(this), receiver, mintTokens);
}Note: mintExternal() is not vulnerable as it overwrites receiver.
Internal Pre-conditions
- User needs to be blacklisted by the protocol
- Another non-blacklisted user needs to call mint()with blacklisted user as receiver
External Pre-conditions
None
Attack Path
- Alice gets blacklisted for malicious activity
- Alice cannot directly call mint()due to blacklist check on minter
- Bob (non-blacklisted) calls mToken.mint(amount, Alice, minOut)
- beforeMTokenMint()only checks Bob's blacklist status
- Alice successfully receives mTokens: accountTokens[receiver] = accountTokens[receiver] + mintTokens
- Alice now holds mTokens despite being blacklisted
Impact
Blacklisted users can bypass restrictions and keep using the protocol through other users, breaking the blacklist system.
- Blacklisted users get mTokens through third-party minting
- They cannot transfer mTokens due to blacklist check in beforeMTokenTransfer()
- But they still earn MALDA rewards based on their mToken balance
- They can claim all earned MALDA rewards since claimMalda()has no blacklist check
- Blacklist only blocks direct actions but not reward earning and claiming
PoC
// Add to test/unit/mErc20/mErc20_mint.t.sol
function test_BlacklistBypass_MintOnBehalf() external whenMarketIsListed(address(mWeth)) {
    address alice = address(0xa11ce);
    address bob = address(0xb0b);
    
    // Setup: Give Bob tokens
    _getTokens(weth, bob, LARGE);
    vm.prank(bob);
    weth.approve(address(mWeth), LARGE);
    
    // Blacklist Alice
    blacklister.blacklistUser(alice);
    assertTrue(blacklister.isBlacklisted(alice));
    
    // Alice cannot mint directly
    vm.prank(alice);
    vm.expectRevert(OperatorStorage.Operator_UserBlacklisted.selector);
    mWeth.mint(SMALL, alice, SMALL);
    
    // But Bob can mint FOR Alice
    uint256 aliceBalanceBefore = mWeth.balanceOf(alice);
    
    vm.prank(bob);
    mWeth.mint(SMALL, alice, SMALL); // receiver = alice
    
    uint256 aliceBalanceAfter = mWeth.balanceOf(alice);
    
    // Alice received mTokens despite being blacklisted
    assertGt(aliceBalanceAfter, aliceBalanceBefore);
    assertGt(aliceBalanceAfter, 0);
}Mitigation
Check both minter and receiver in beforeMTokenMint():
function beforeMTokenMint(address mToken, address minter, address receiver) 
    external override 
    onlyAllowedUser(minter) 
    ifNotBlacklisted(minter) 
+   ifNotBlacklisted(receiver)
{
    // ...
}Metadata
Metadata
Assignees
Labels
No labels