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

4 stars 2 forks source link

Malicious IBTs could corrupt ibtRate if Spectra solely relies on the IBT's state #158

Closed c4-bot-8 closed 8 months ago

c4-bot-8 commented 8 months ago

Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L641-L651 https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L152 https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L902

Vulnerability details

Impact

Spectra's ibtRate calculation relies solely on the IBT contract's state - specifically totalAssets and balanceOf Spectra's contract. This leaves it vulnerable to manipulation if the IBT contract's state is changed unexpectedly.

If ibtRate is reduced, users depositing IBT into Spectra would get more shares than they should. If ibtRate then corrects back, those users could withdraw and profit.

There are several IBT external functions that could alter the critical state values used by Spectra:

function transfer

function transferFrom

function withdraw

function redeem

function mint

If any user calls these functions, it would change the IBT's totalAssets and Spectra's balance - thus directly affecting ibtRate.

For example, let's imagine Spectra holds 100 IBT initially. The ibtRate will be calculated based on 100 IBT totalAssets and Spectra's balanceOf 100 IBT.

But if another user calls IBT.transferFrom(Spectra, user, 50):

This would cut the ibtRate in half unexpectedly!

Proof of Concept

function _previewDepositIBT

This allows an attacker to arbitrarily manipulate the ibtRate used by the Spectra protocol. By changing ibtRate, they can extract profits or cause loss of funds for Spectra users.

The ibtRate relies solely on the IBT contract's state

PrincipalToken.sol#L 152

ibtRate = IERC4626(ibt).previewRedeem(ibtUnit).toRay(_assetDecimals);

PrincipalToken.sol#L 902

// _getCurrentPTandIBTRates
uint256 currentIBTRate = IERC4626(ibt).previewRedeem(ibtUnit).toRay(_assetDecimals);

By solely relying on the IBT contract's state, ibtRate can be manipulated via IBT's external functions.

An attacker can call IBT external functions to alter its state and corrupt ibtRate:

IBT.transferFrom(Spectra, attacker, 50 IBTs) 

// Spectra balance now 50 IBT
// totalAssets still 100 IBT
// ibtRate cut in half!

This allows the attacker to extract profit. For example:

Attacker reduces ibtRate by 50% using transferFrom User deposits 100 IBT into Spectra when ibtRate is artificially reduced User gets double the normal shares due to reduced ibtRate Attacker restores ibtRate to normal User can now withdraw and profit

Tools Used

Manual review

Recommended Mitigation Steps

Spectra should only integrate with trusted, standardized IBTs without risky features. Validate totalAssets matches Spectra's deposit/withdraw accounting expectations. Possibly read balanceOf(spectrasContract) from IBT after sensitive operations as a sanity check. Consider using a price oracle or Chainlink as redundancy on ibtRate.

Assessed type

Governance

c4-pre-sort commented 8 months ago

gzeon-c4 marked the issue as insufficient quality report

c4-pre-sort commented 8 months ago

gzeon-c4 marked the issue as primary issue

c4-judge commented 8 months ago

JustDravee marked the issue as unsatisfactory: Invalid