Users can freely set ibtRate without depositing ibt or buying YT. They are assured of a risk-free instant yield when the ibtrate rises and they can potentially drain the entire contract balance with the use of flash loans.
Audit: 2024-02-spectra-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L340-L366
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L385-L391
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L609-L631
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/YieldToken.sol#L71-L77
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/libraries/PrincipalTokenUtil.sol#L55-L130


# Vulnerability details

## Impact

The yield on a YT is calculated by taking the difference between the stored ibtRate of the user and the currenct ibtRate. It is assumed that these rates are only set when the user interacts with the protocol by either depositing ibt/assets or buying YT.

However, the `updateYield(address user)` function is public and has no access control, allowing anyone to set `ibtRateOfUser[_user]` whenever they wish.

This allows a strategic user to set the ibtRate whenever it is extremely low at no cost, wait for the ibtRate to recover/increase and then use a flashloan make an instant gigantic profit in one transaction by buying YT, claiming yield and selling the YT. This can be chained for a set of accounts, repeating the same process untill the contract balance is drained. 


## Proof of Concept

When we look at the `updateYield` function, we can see that anyone can call the function and set `ibtRateOfUser[_user]` and `ptRateOfUser[_user]` to the current market values.   

There is no check to assure that the caller has any PT or YT in his possession.  

``` solidity
    function updateYield(address _user) public override returns (uint256 updatedUserYieldInIBT) {
        (uint256 _ptRate, uint256 _ibtRate) = _updatePTandIBTRates();

        uint256 _oldIBTRateUser = ibtRateOfUser[_user];
        if (_oldIBTRateUser != _ibtRate) {
            ibtRateOfUser[_user] = _ibtRate;
        }
        uint256 _oldPTRateUser = ptRateOfUser[_user];
        if (_oldPTRateUser != _ptRate) {
            ptRateOfUser[_user] = _ptRate;
        }

        // Check for skipping yield update when the user deposits for the first time or rates decreased to 0.
        if (_oldIBTRateUser != 0) {
            updatedUserYieldInIBT = PrincipalTokenUtil._computeYield(
                _user,
                yieldOfUserInIBT[_user],
                _oldIBTRateUser,
                _ibtRate,
                _oldPTRateUser,
                _ptRate,
                yt
            );
            yieldOfUserInIBT[_user] = updatedUserYieldInIBT;
            emit YieldUpdated(_user, updatedUserYieldInIBT);
        }
    }
``` 

For an IBT token with a volatile rate between 1 - 50.   

Alice calls `updateYield(address Alice)` when the ibtRate is 1.   

`ibtRateOfUser[Alice]` = 1.  

She then