Skip to content

Latest commit

 

History

History
81 lines (60 loc) · 2.7 KB

File metadata and controls

81 lines (60 loc) · 2.7 KB

Brisk Cherry Aphid

Medium

Morpho allows onBehalf repayment which can be weaponized to dos full repayment

Summary

Malicious users can frontrun calls to fully delever through deleverToZeroBorrowBalance by repaying dust amounts on behalf of the settoken to continously grief the repayment process.

Root Cause

deleverToZeroBorrowBalance calls the _repayBorrow function which invokes repay in Morpho.

https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/2f125406e0dd3b1fc029b9a47fe97bfbf906fce2/index-protocol/contracts/protocol/modules/v1/MorphoLeverageModule.sol#L733C1-L759C6

    function _repayBorrow(
        ISetToken _setToken,
        MarketParams memory _marketParams,
        uint256 _notionalQuantity,
        uint256 _shares
    )
//... 
        } else {
            _setToken.invokeApprove(_marketParams.loanToken, address(morpho), _notionalQuantity);
>>          _setToken.invokeRepay(
                morpho,
                _marketParams,
                _notionalQuantity,
                0
            );
        }
    }

https://github.com/morpho-org/morpho-blue/blob/d60e123cd7e0bb1b39df7369847717237a7751cd/src/Morpho.sol#L286s

Morpho's repay function is public, allowing users to repay on behalf of anyone, without any limit on how little the amount can be. From the implementation we can see that anyone could repay any other user's debt(or part of it). So when the manager tries to repay the full amount a malicious user could just front-run the transaction and repay 1 wei on behalf of the connector address, thus reverting the transaction due to underflow.

    function repay(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        bytes calldata data
    ) external returns (uint256, uint256) {
        Id id = marketParams.id();
        require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
        require(UtilsLib.exactlyOneZero(assets, shares), ErrorsLib.INCONSISTENT_INPUT);
        require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);

        _accrueInterest(marketParams, id);

        if (assets > 0) shares = assets.toSharesDown(market[id].totalBorrowAssets, market[id].totalBorrowShares);
        else assets = shares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);

>>>     position[id][onBehalf].borrowShares -= shares.toUint128();
//...
    }

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

Full repayment DOS due to frontrun.

PoC

No response

Mitigation

Check the shares owned and if they are less than the amount passed to repay, repay just the shares owned