Cheesy Fossilized Snail
Medium
Front-Running Vulnerability in repayBorrow FunctionAn attacker can front-run the _repayBorrow transaction to manipulate the exchange rate between assets and shares, potentially causing a loss of funds for the SetToken
The _repayBorrow function in MorphoLeverageModule.sol allows repayment using either asset amounts or share amounts, but not both simultaneously. This design can be exploited by a malicious actor to front-run the transaction and manipulate the exchange rate between assets and shares, potentially causing the SetToken to repay more than necessary or receive fewer shares than expected.
the _repayBorrow function uses an if-else statement to decide whether to repay based on shares or assets. This mutually exclusive approach creates a window of opportunity for front-running attacks.
check code snippet https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-protocol/contracts/protocol/modules/v1/MorphoLeverageModule.sol#L742-L760
The SetToken must have an outstanding borrow position on Morpho. The _repayBorrow function must be called as part of a larger transaction (e.g., within the delever function).
The attacker must have the ability to monitor the mempool and quickly submit transactions. The Morpho protocol must allow for rapid changes in the asset-to-share ratio.
The SetToken initiates a delever transaction that includes a call to _repayBorrow. An attacker observes this pending transaction in the mempool. The attacker quickly submits a transaction to manipulate the asset-to-share ratio on Morpho (e.g., by making a large deposit or withdrawal). The attacker's transaction is mined before the SetToken's transaction. The SetToken's _repayBorrow transaction is executed with the manipulated asset-to-share ratio.
The SetToken could suffer a loss of funds due to overpayment or undervaluation of its repayment. The exact impact would depend on the size of the borrow position and the degree of manipulation in the asset-to-share ratio.
sample test case
function simulateFrontRunningAttack() public {
// Assume SetToken is about to call delever which includes _repayBorrow
uint256 initialRatio = morpho.getAssetToShareRatio(marketId);
// Attacker manipulates the ratio
attacker.manipulateRatio(marketId);
uint256 manipulatedRatio = morpho.getAssetToShareRatio(marketId);
// SetToken's _repayBorrow executes with manipulated ratio
setToken.delever(...);
// Check the difference in repayment amount or received shares
// This difference represents the potential loss to the SetToken
}
Implement a slippage protection mechanism in the _repayBorrow function. Consider using both assets and shares in the repayment to ensure a fair exchange rate. Implement a commit-reveal scheme for repayments to prevent front-running.
Example mitigation:
function _repayBorrow(
ISetToken _setToken,
MarketParams memory _marketParams,
uint256 _notionalQuantity,
uint256 _shares,
uint256 _maxSlippage
)
internal
{
uint256 initialRatio = morpho.getAssetToShareRatio(_marketParams.id());
_setToken.invokeApprove(_marketParams.loanToken, address(morpho), _notionalQuantity);
_setToken.invokeRepay(
morpho,
_marketParams,
_notionalQuantity,
_shares
);
uint256 finalRatio = morpho.getAssetToShareRatio(_marketParams.id());
require(finalRatio <= initialRatio * (1 + _maxSlippage), "Slippage too high");
}