The LendingPool contract contains a critical flaw in its collateral validation logic that allows users to borrow significantly more than their collateral ratio should permit. Due to a reversed comparison in the collateralization check, borrowers can repeatedly borrow amounts that would typically exceed their maximum borrowing capacity, potentially leading to undercollateralized positions and protocol insolvency.
The issue exists in the LendingPool.sol::borrow()
function where the collateralization check is implemented incorrectly:
This check compares whether the collateral value is less than the scaled debt value (userTotalDebt * liquidationThreshold), which is the inverse of the correct comparison. The proper validation should ensure that the new total debt after borrowing remains below the maximum allowed by the collateral value.
For example, with a liquidation threshold of 80%, a user with 100,000 in collateral should only be able to borrow up to 80,000; for simplicity, lets assume usageIndex = 1.0.
However, the current implementation allows users to borrow beyond this limit because the check is reversed, essentially comparing 100,000 < (90,000 * 0.8) which evaluates to 100,000 < 72,000, allowing the transaction to proceed when it should revert.
Additionally, because a user must be flagged for liquidation through LendingPool.sol::initiateLiquidation()
function call, the user in one txn can call borrow infinitesimally until the check reaches 100,000, by which point they would have far exceeded their collateral value.
Building from the last example, a user then calls LendingPool.sol::borrow()
with amount = 15,000.
This check will pass because the user hasn't been flagged for liquidation yet.
userTotalDebt
== 105,000.
Thereafter, the check will evaluate to:
100000 < 105000 * 0.8 = 84000
. At this point, they've already taken out a a loan greater than the principle but are able to continue until the check fails.
High
The vulnerability is easily exploitable as it requires no special conditions or complex setup. Any user with deposited collateral can execute this attack by making multiple borrow calls in the same transaction before liquidation checks occur. The bug exists in a core function that will be frequently used, making it highly likely to be discovered and exploited.
High
This vulnerability allows users to:
Borrow significantly more than their collateral should permit
Potentially drain the protocol's lending pools
Lead to bad debt accumulation and protocol insolvency
Convert the project into a foundry project, ensuring test in foundry.toml points to a designated test directory.
Comment out the forking object from the hardhat.congif.cjs
file:
Copy the following test into the directory:
Run Forge test
Output:
The collateralization check should be modified to ensure the new total debt remains under the maximum allowed borrowing power
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.