code-423n4 / 2024-02-spectra-findings

4 stars 2 forks source link

Lack of protection against repeated `_updatePTandIBTRates` calls allows attackers to arbitrarily drain PT rate. #188

Closed c4-bot-5 closed 8 months ago

c4-bot-5 commented 8 months ago

Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L879-L894

Vulnerability details

Impact

_updatePTandIBTRates method that decreases the PT rate has no protection against unbounded/repeated calls. An attacker could manipulate the parameters to _computeYield to generate arbitrary negative yield amounts. They could then call _updatePTandIBTRates repeatedly to drain the PT rate to 0.

For example, they could:

  1. Deposit tokens into the protocol to mint PT shares.

  2. Borrow a flash loan of IBT tokens.

  3. Use the flash loaned IBT to manipulate the IBT rate oracle downwards.

  4. Call _computeYield with the manipulated rate to generate a large negative yield amount.

  5. Call _updatePTandIBTRates to decrease PT rate based on the false negative yield.

  6. Return flash loan and repeat process in a loop draining PT rate to 0.

  7. Redeem PT shares for underlying assets while PT rate is 0.

This allows an attacker to arbitrarily drain value from the protocol by exploiting unbounded _updatePTandIBTRates calls.

The reason is that protection against repeated _updatePTandIBTRates calls in a single transaction.

The attacker can drain PT rate to 0 via unbounded manipulation.

The lack of protection against repeated _updatePTandIBTRates calls allows attackers to arbitrarily drain the PT rate to 0. This could enable attackers to extract full collateral value from the protocol after manipulating the rate.

Proof of Concept

The _updatePTandIBTRates method decreases the ptRate based on detected negative yield. However, there is no limit on how many times it can be called in a single transaction. The issue is _updatePTandIBTRates lacks a counter or limit on repeated calls: File: src/tokens/PrincipalToken.sol::_updatePTandIBTRates

function _updatePTandIBTRates() internal returns (uint256 _ptRate, uint256 _ibtRate) {
    if (block.timestamp >= expiry) {
        if (!ratesAtExpiryStored) {
            storeRatesAtExpiry();
        }
    }

    // Decrease ptRate based on detected negative yield 
    (_ptRate, _ibtRate) = _getPTandIBTRates(false);
    if (block.timestamp < expiry) {
        if (_ibtRate != ibtRate) {
            ibtRate = _ibtRate;
        }
        if (_ptRate != ptRate) {
            ptRate = _ptRate;
        }
    }
    // No protection against repeated calls
}

Summary

Lack of protection against repeated _updatePTandIBTRates calls allows attackers to arbitrarily drain PT rate. This could lead to loss of collateral value from the protocol.

Tools Used

Vs

Recommended Mitigation Steps

Add a ptRateUpdateCount state variable and limit _updatePTandIBTRates to 1 call per transaction.

Assessed type

Reentrancy

c4-pre-sort commented 8 months ago

gzeon-c4 marked the issue as sufficient quality report

c4-pre-sort commented 8 months ago

gzeon-c4 marked the issue as primary issue

c4-pre-sort commented 8 months ago

gzeon-c4 marked the issue as insufficient quality report

gzeon-c4 commented 8 months ago

rate updated before redeem

c4-judge commented 8 months ago

JustDravee marked the issue as unsatisfactory: Invalid