- 
                Notifications
    You must be signed in to change notification settings 
- Fork 0
Description
Jumpy Pistachio Butterfly
Medium
Wrong units in outflow USD limiter withdraw path can cause bypass of outflow cap
Summary
Passing mToken units to the USD outflow limiter will cause a cap bypass for the protocol as a user withdraws, because the limiter expects underlying units but is checked before converting mTokens via redeem.
Root Cause
In mErc20Host.performExtensionCall(uint256 actionType, uint256 amount, uint32 dstChainId) the code calls:
https://github.com/sherlock-audit/2025-07-malda/blob/1bd22b27698052c24299dfab68a735810562e302/malda-lending/src/mToken/host/mErc20Host.sol#L290-L293
CommonLib.checkHostToExtension(amount, ...)
then _checkOutflow(amount (here amount is mTokens for withdraw)
then for actionType == 1 performs uint256 _amount = _redeem(msg.sender, amount, false); which returns underlying.
if (actionType == 1) {
            _amount = _redeem(msg.sender, amount, false);
            emit mErc20Host_WithdrawOnExtensionChain(msg.sender, dstChainId, _amount);
        }The issue is that the _checkOutflow check was performed on the mToken amount, not underlying.
Internal Pre-conditions
None (other than an exchangeRate > 1e18)
External Pre-conditions
None
Attack Path
USD cap window = $100. Exchange rate = 2e18 (1 mToken = 2 underlying).
User calls performExtensionCall(1 /withdraw/, 60 /mTokens/, dst)
_checkOutflow(60) passes (60 < 100).
_redeem(..., 60, ...) returns 120 underlying.
The protocol ships $120 cross-chain in a window capped at $100.
Impact
The protocol-wide USD outflow cap can be exceeded approximately by the exchange rate, enabling larger-than-intended drains to extension chains. This increases the risk of liquidity shortfalls and cross-chain imbalances.
PoC
N/A
Mitigation
Move the check after redeem and pass underlying:
if (actionType == 1) {
    uint256 underlyingOut = _redeem(msg.sender, amount /* mTokens */, false);
    _checkOutflow(underlyingOut);
    acc[dstChainId].outPerChain[msg.sender] += underlyingOut;
}