Total debt could exceed the debt ceiling due to interest accrual
Opened this issue · 0 comments
Lines of code
Vulnerability details
Impact
The inconsistent enforcement of the debt ceiling can lead to a situation where the actual total debt, including accrued interest, exceeds the intended debt ceiling. This discrepancy can potentially destabilize the system's economic model and risk parameters, leading to:
- Increased systemic risk due to higher-than-expected debt levels.
- Potential insolvency if the collateral value doesn't cover the actual debt.
- Misrepresentation of the system's financial state to users and stakeholders.
- Violation of the protocol's core invariants and economic assumptions.
Proof of Concept
Inconsistent debt ceiling enforcement in PoolV3.sol, the debt ceiling is enforced when lending, but not when interest accrues. This could lead to a situation where the total debt exceeds the debt ceiling due to interest accrual:
The debt ceiling is enforced only on the principal, not including accrued interest.
Accrued interest is calculated but not factored into debt updates or ceiling checks.
This could lead to a situation where the actual debt (principal + accrued interest) exceeds the debt ceiling, both at the vault level and system-wide.
if (borrowedAmount == 0 || cmBorrowed_ > cmDebt.limit || totalBorrowed_ > _totalDebt.limit) {
revert CreditManagerCantBorrowException(); // U:[LP-2C,13A]
}The issue stems from the fact that while new borrowing is restricted by the debt ceiling, accrued interest is not factored into this limit. Over time, as interest accrues, the total debt can silently grow beyond the set ceiling.
Breakdown the issue:
-
Initial state:
- Debt ceiling: 1,000,000 DAI
- Current total borrowed: 900,000 DAI
- Current accrued interest: 0 DAI
-
A user attempts to borrow 150,000 DAI
-
Time passes, and interest accrues
-
Current state:
- Debt ceiling: 1,000,000 DAI (unchanged)
- Current total borrowed: 900,000 DAI (unchanged)
- Current accrued interest: 80,000 DAI
- Actual total debt: 980,000 DAI
-
A user now attempts to borrow 30,000 DAI
-
Final results:
- Debt ceiling: 1,000,000 DAI
- Current total borrowed: 930,000 DAI
- Current accrued interest: 80,000 DAI
- Actual total debt: 1,010,000 DAI
The actual total debt now exceeds the debt ceiling by 10,000 DAI, violating the intended limit.
Tools Used
Manual Review
Recommended Mitigation Steps
Modify the lendCreditAccount function in PoolV3.sol to include accrued interest in the debt ceiling check:
function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external override creditManagerOnly whenNotPaused nonReentrant {
uint128 borrowedAmountU128 = borrowedAmount.toUint128();
uint256 totalAccruedInterest = calculateTotalAccruedInterest();
DebtParams storage cmDebt = _creditManagerDebt[msg.sender];
uint128 totalBorrowed_ = _totalDebt.borrowed + borrowedAmountU128;
uint128 cmBorrowed_ = cmDebt.borrowed + borrowedAmountU128;
if (borrowedAmount == 0 || cmBorrowed_ > cmDebt.limit || (totalBorrowed_ + totalAccruedInterest) > _totalDebt.limit) {
revert CreditManagerCantBorrowException();
}
// ... rest of the function
}This change ensures that the debt ceiling check includes both the borrowed amount and the total accrued interest, preventing the actual total debt from exceeding the set limit.
Assessed type
Other