Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Daily limit invariant can break when setting limits without daily limit updates #424

Open
c4-bot-4 opened this issue Mar 15, 2024 · 6 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-367 grade-a insufficient quality report This report is not of sufficient quality QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax 🤖_78_group AI based duplicate group recommendation

Comments

@c4-bot-4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol?plain=1#L807-L833
https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol?plain=1#L1246-L1268

Vulnerability details

Impact

A vault owner has the capability to update the daily limits for both lending and debt increases by invoking the Vault.setLimits() function. Upon calling this function, any changes made to either dailyLendIncreaseLimitMin or dailyDebtIncreaseLimitMin will not apply retroactively for the upcoming cycle. However, if there's no change in the daily limit values, the limits will still be enforced. This behavior can potentially lead to situations where the daily limit increases by up to twice the expected amount, thereby compromising the integrity of the daily limit rule.

Proof of Concept

One of the major usages of setLimits() is to set the lending/debt limits to zero. This acts as a halt on debt/lending operations when an emergency occurs. This feature works as expected. However, a problem occurs if the protocol calls Vault.setLimits() and doesn't update either daily limit value.

I will make the following assumption:

It is reasonable to assume that not all values will always be updated at once. For example, the protocol may just want to update the minimum size of a loan.

Now let's review both daily limit functions below:

function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal {
    // daily lend limit reset handling
    uint256 time = block.timestamp / 1 days;
    if (force || time > dailyLendIncreaseLimitLastReset) {
        uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up)
            * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32;
        dailyLendIncreaseLimitLeft =
            dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit;
        dailyLendIncreaseLimitLastReset = time;
    }
}

function _resetDailyDebtIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal {
    // daily debt limit reset handling
    uint256 time = block.timestamp / 1 days;
    if (force || time > dailyDebtIncreaseLimitLastReset) {
        uint256 debtIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up)
            * (Q32 + MAX_DAILY_DEBT_INCREASE_X32) / Q32;
        dailyDebtIncreaseLimitLeft =
            dailyDebtIncreaseLimitMin > debtIncreaseLimit ? dailyDebtIncreaseLimitMin : debtIncreaseLimit;
        dailyDebtIncreaseLimitLastReset = time;
    }
}

Both functions are nearly identical so let's focus on discussing just _resetDailyDebtIncreaseLimit(). When Vault.setLimits() is called, the admin may or may not update the value of dailyDebtIncreaseLimitMin. Regardless if it's updated or not, Vault.setLimit() forces an update for both daily limits by setting the force argument to true.

function setLimits(
    uint256 _minLoanSize,
    uint256 _globalLendLimit,
    uint256 _globalDebtLimit,
    uint256 _dailyLendIncreaseLimitMin,
    uint256 _dailyDebtIncreaseLimitMin
) external {
    ...
    dailyLendIncreaseLimitMin = _dailyLendIncreaseLimitMin;
    dailyDebtIncreaseLimitMin = _dailyDebtIncreaseLimitMin;

    (, uint256 newLendExchangeRateX96) = _updateGlobalInterest();

    // force reset daily limits with new values
    // AUDIT: daily limit increases are forced, regardless if the value is updated.
    _resetDailyLendIncreaseLimit(newLendExchangeRateX96, true);
    _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, true);
    
    ...
}

By forcing an update when the _dailyDebtIncreaseLimitMin hasn't changed, the daily limit will automatically be reset and users will be able to at most increase the daily limit up to 2x.

Tools Used

Manual inspection.

Recommended Mitigation Steps

The protocol should check if the _dailyDebtIncreaseLimitMin has changed since the last update. If there is a change, then force an update. Otherwise, do nothing.

Assessed type

Other

@c4-bot-4 c4-bot-4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Mar 15, 2024
c4-bot-4 added a commit that referenced this issue Mar 15, 2024
@c4-bot-12 c4-bot-12 added the 🤖_78_group AI based duplicate group recommendation label Mar 15, 2024
@c4-pre-sort
Copy link

0xEVom marked the issue as duplicate of #367

@c4-pre-sort
Copy link

0xEVom marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added sufficient quality report This report is of sufficient quality insufficient quality report This report is not of sufficient quality and removed sufficient quality report This report is of sufficient quality labels Mar 21, 2024
@c4-pre-sort
Copy link

0xEVom marked the issue as insufficient quality report

@c4-judge c4-judge removed the 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value label Mar 31, 2024
@c4-judge
Copy link

jhsagd76 changed the severity to QA (Quality Assurance)

@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax labels Mar 31, 2024
@jhsagd76
Copy link

jhsagd76 commented Apr 1, 2024

2L-B

@c4-judge
Copy link

c4-judge commented Apr 1, 2024

jhsagd76 marked the issue as grade-a

@C4-Staff C4-Staff reopened this Apr 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-367 grade-a insufficient quality report This report is not of sufficient quality QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax 🤖_78_group AI based duplicate group recommendation
Projects
None yet
Development

No branches or pull requests

6 participants