The StabilityPool
contract contains a critical calculation error in its liquidation process StabilityPool.liquidateBorrower
where debt values are improperly scaled using multiplication instead of division. This leads to:
Over-inflated Debt Checks: Causes valid liquidations to fail unnecessarily when pool balances are sufficient for actual debt but not the inflated amount
Dangerous Token Approvals: Leaves residual allowances that could be exploited in future protocol upgrades
The vulnerability stems from mismatched scaling logic compared to the system's DebtToken._update
implementation, creating protocol-level risks despite no immediate fund loss in the current version. Fixing this requires correcting the scaling operation and implementing safe allowance practices.
The liquidation process in StabilityPool.liquidateBorrower
contains an inverted scaling calculation that creates protocol risks. The vulnerability exists in the debt scaling logic at StabilityPool.sol#L453 where:
Incorrect Scaling Operation: The code uses rayMul
with the normalized debt index instead of rayDiv
, creating an over-inflated debt value
Mismatch with DebtToken Logic: This contradicts the established scaling pattern seen in DebtToken._update
(DebtToken.sol#L256-L264) which correctly uses rayDiv
for debt scaling
The core issue stems from:
getUserDebt()
returns actual debt (scaledDebt × index)
getNormalizedDebt()
returns the current index
Using multiplication instead of division creates a squared index multiplier (debt × index²)
This manifests two critical effects:
Insufficient Balance False Positives: The inflated scaledUserDebt
causes unnecessary reverts when pool balance covers actual debt but not the inflated value
Residual Allowance Risk: Over-approval leaves dangerous residual allowances that could be exploited by future protocol upgrades or added functionality
While the current LendingPool implementation correctly transfers only the actual debt amount, the residual approval remains as protocol-level technical debt that violates security best practices for token approvals.
This vulnerability creates two primary negative impacts on protocol operations:
Operational Failure Risk
Legitimate liquidations will fail when:
actualDebt ≤ poolBalance < inflatedDebt
This leaves undercollateralized positions active, threatening protocol solvency during market downturns.
Approval Poisoning
Persistent residual allowances create:
Technical debt requiring future cleanup
Potential exploit vectors for any new functionality interacting with StabilityPool's crvUSD approvals
Violation of least-privilege principle for token allowances
Severity Classification: Medium
While no immediate fund loss occurs in the current implementation, the combination of failed liquidations and dangerous approval patterns creates systemic risk that violates security best practices and threatens long-term protocol health.
Manual Review
Correct Scaling Calculation
Modify the debt scaling logic in StabilityPool.liquidateBorrower
(StabilityPool.sol#L453) to:
This aligns with the established pattern in DebtToken._update
and properly converts actual debt to scaled terms.
Safe Allowance Management
Implement allowance cleanup after liquidation:
This follows the best practice of resetting allowances to prevent residual permissions.
These changes maintain protocol integrity while eliminating both the operational failure risk and approval poisoning vectors.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.