This repository has been archived by the owner on Apr 28, 2024. It is now read-only.
panprog - Borrower
's modify
, liquidate
and warn
functions use stored (outdated) account liabilities which makes it possible for the user to intentionally put him into bad debt in 1 transaction
#41
Labels
Has Duplicates
A valid issue with 1+ other issues describing the same vulnerability
High
A valid High severity issue
Reward
A payout will be made for this issue
Sponsor Confirmed
The sponsor acknowledged this issue is valid
Will Fix
The sponsor confirmed this issue will be fixed
panprog
high
Borrower
'smodify
,liquidate
andwarn
functions use stored (outdated) account liabilities which makes it possible for the user to intentionally put him into bad debt in 1 transactionSummary
Borrower._getLiabilities()
function returns stored borrow balance:Stored balance is the balance at the last interest settlement, which is different (less) than current balance if there were no transactions accuring interest for this lender for some time. This means that this function returns outdated liabilities. For example:
t=100: borrower1 borrows 10000 USDT
... no transactions
t=200: borrower1 borrowBalance = 10000.1 USDT (due to accured interest), but borrowBalanceStored = 10000 USDT (the amount at last interest accural).
_getLiabilities
function is used byBorrower
'smodify
,liquidate
andwarn
functions, meaning that it works on outdated account borrow balances (liabilities), including health check. This leads to multiple problems, such as:warn
andliquidate
will revert trying to liquidate some accounts which just became unhealthy but were healthy at the last interest accuralliquidate
will not repay full account borrowBalancesmodify
will allow account to be unhealthy after the actions it performs, if it's healthy using outdated stored borrow balancesThe first 2 problems can be worked around by calling
Lender.accrueInterest
beforewarn
orliquidation
, which will settle interest rate fixing this problem. However, the 3rd issue is a lot more serious and can't be worked around as it allows malicious user to intentionally create bad debt in 1 transaction which will cause loss of funds for the other users.Vulnerability Detail
Possible scenario for the intentional creation of bad debt:
borrowBalance
is greater thanborrowBalanceStored
by a value higher thanMAX_LEVERAGE
(example: borrowBalance = 10630 DAI, borrowBalanceStored = 10000 DAI)modify
and withdraw max possible amount (based onborrowBalanceStored
), for example, withdraw 1000 DAI (remaining assets = 10051 DAI, which is healthy based on stored balance of 10000 DAI, but in fact this is already a bad debt, because borrow balance is 10630, which is more than remaining assets). This works, because liabilities used are outdated.At this point the user is already in bad debt, but due to points 1-2, it's still not liquidatable. After calling
Lender.accrueInterest
the account can be liquidated. This bad debt caused is the funds lost by the other users.This scenario is not profitable to the malicious user, but can be modified to make it profitable: the user can deposit large amount to lender before these steps, meaning the inflated interest rate will be accured by user's deposit to lender, but it will not be paid by the user due to bad debt (user will deposit 1051 DAI, withdraw 1000 DAI, and gain some share of accured 630 DAI, for example if he doubles the lender's TVL, he will gain 315 DAI - protocol fees).
Impact
Malicious user can create bad debt to his account in 1 transaction. Bad debt is the amount not withdrawable from the lender by users who deposited. Since users will know that the lender doesn't have enough assets to pay out to all users, it can cause bank run since first users to withdraw from lender will be able to do so, while those who are the last to withdraw will lose their funds.
Proof of concept
The scenario above is demonstrated in the test, create test/Exploit.t.sol:
Execution console log:
As can be seen, in the end user debt is 579 DAI with 0 assets.
Code Snippet
Borrower._getLiabilities()
returns stored balances:https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Borrower.sol#L527-L530
borrowBalanceStored
usesborrowIndex
(which is index at last accural):https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Ledger.sol#L226-L232
For comparision,
borrowBalance
uses_previewInterest
to get current borrow balance:https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Ledger.sol#L216-L223
Borrower.warn
uses_getLiabilities
:https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Borrower.sol#L166
liquidate
uses_getLiabilities
:https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Borrower.sol#L211
modify
also uses_getLiabilities
:https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Borrower.sol#L314
Tool used
Manual Review
Recommendation
Consider using
borrowBalance
instead ofborrowBalanceStored
in_getLiabilities()
.The text was updated successfully, but these errors were encountered: