- 
                Notifications
    You must be signed in to change notification settings 
- Fork 0
Description
Tricky Navy Bird
High
Complete Market DoS via Division by Zero in utilizationRate() Function When Reserves Exceed or Equal Available Cash
Summary
The utilizationRate() function contains a critical mathematical flaw that allows attackers to permanently disable entire lending markets. When reserves equal or exceed the sum of cash and borrows, the function either reverts due to arithmetic underflow or division by zero, making all market operations impossible.
Root Cause
Two Failure Scenarios:
Arithmetic Underflow (when reserves > cash + borrows)
Denominator becomes negative: (cash + borrows - reserves) < 0
Solidity 0.8+ reverts on underflow
Division by Zero (when reserves = cash + borrows)
Denominator becomes zero: (cash + borrows - reserves) = 0
Division by zero causes revert
function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves) public pure override returns (uint256) {
if (borrows == 0) {
return 0;
}
return borrows * 1e18 / (cash + borrows - reserves); // ← VULNERABLE LINE
}
code snippet -https://github.com/sherlock-audit/2025-07-malda/blob/798d00b879b8412ca4049ba09dba5ae42464cfe7/malda-lending/src/interest/JumpRateModelV4.sol#L96-L109
Internal Pre-conditions
Market is empty (cash=0, borrows=0, reserves=0).
External Pre-conditions
No one mint any token on that market.
Attack Path
Simple Attack (Empty Market):
Step 1: Market starts empty (cash=0, borrows=0, reserves=0)
Step 2: Attacker donates X tokens via _addReserves()
→ cash = X, borrows = 0, reserves = X
Step 3: Attacker supplies collateral in another market
Step 4: Attacker borrows small amount B from target market
→ cash = X-B, borrows = B, reserves = X
→ Denominator = (X-B) + B - X = 0
Where B is as small as possible [1] . Because interest will acquire over the time. Attacker will borrow small amount to DoS for long period of time.
Step 5: Market is now DoSed.
Mathematical Example:
Initial: cash = 0, borrows = 0, reserves = 0
After Donate:  cash = 1000, borrows = 0, reserves = 1000
After Borrow:  cash = 999, borrows = 1, reserves = 1000
Calculation: (999 + 1 - 1000) = 0
Result: Division by zero → REVERT  { borrows * 1e18 / (totalSupply - reserves)}
Impact
No new lending - All operations frozen
Admin helpless - Even emergency functions fail
PoC
NA
Mitigation
Add proper validation to prevent the DoS condition:
function utilizationRate(uint256 cash, uint256 borrows, uint256 reserves)
public pure override returns (uint256) {
if (borrows == 0) {
return 0;
}
uint256 totalSupply = cash + borrows;
// Prevent DoS: ensure denominator is positive
require(totalSupply > reserves, "Insufficient available cash");
return borrows * 1e18 / (totalSupply - reserves);
}
Lead judge reply --
That is not epxloitable in any way practically, thanks to the borrow risk control parameters.
Author Reply --
I disagree with your comment "That is not epxloitable in any way practically, thanks to the borrow risk control parameters." This is a Duplicate Report of #1409 [https://audits.sherlock.xyz/contests/1029/voting/1409]