Anyone can lock in potentially arbitrary rates for redeeming principal tokens after expiry by calling storeRatesAtExpiry(). This could allow attackers to manipulate redemptions to their advantage.
The severity is high because it impacts a critical part of the contract's functionality for redeeming tokens after expiry. Allowing anyone to determine the conversion rates means the rates could potentially be set to completely arbitrary values, enabling theft of funds or making redemptions impossible if rates are set to zero.
Proof of Concept
The ratesAtExpiryStored flag is not protected by access control. This means that anyone can call the storeRatesAtExpiry() function after expiry.
Here is how it works:
The storeRatesAtExpiry() function is marked with the afterExpiry modifier, which checks that the block timestamp is greater than or equal to the expiry time:
This means that anyone can call the storeRatesAtExpiry() function after the expiry time.
Inside the function, it simply sets the ratesAtExpiryStored flag to true:
function storeRatesAtExpiry() public override afterExpiry {
if (ratesAtExpiryStored) {
revert RatesAtExpiryAlreadyStored();
}
ratesAtExpiryStored = true;
// update rates
emit RatesStoredAtExpiry(...);
}
There is no access control check here to restrict who can call this.
The impact is that anyone can trigger the rate storage after expiry. This could be used by an attacker to manipulate the rates stored if the actual market rates have moved significantly.
For example, an attacker could:
Wait until expiry
Call storeRatesAtExpiry() with the old rates if rates have dropped a lot
Redeem PT for less IBT than they should get
Tools Used
Manual
Recommended Mitigation Steps
The storeRatesAtExpiry() function should be restricted to an authorized role, for example:
function storeRatesAtExpiry() public override afterExpiry restricted {
// add restricted modifier
}
This would prevent unauthorized actors from manipulating the stored rates.
Lines of code
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L409-L417
Vulnerability details
Impact
Anyone can lock in potentially arbitrary rates for redeeming principal tokens after expiry by calling storeRatesAtExpiry(). This could allow attackers to manipulate redemptions to their advantage. The severity is high because it impacts a critical part of the contract's functionality for redeeming tokens after expiry. Allowing anyone to determine the conversion rates means the rates could potentially be set to completely arbitrary values, enabling theft of funds or making redemptions impossible if rates are set to zero.
Proof of Concept
The
ratesAtExpiryStored
flag is not protected by access control. This means that anyone can call thestoreRatesAtExpiry()
function after expiry. Here is how it works: ThestoreRatesAtExpiry()
function is marked with theafterExpiry
modifier, which checks that the block timestamp is greater than or equal to the expiry time:This means that anyone can call the
storeRatesAtExpiry()
function after the expiry time. Inside the function, it simply sets theratesAtExpiryStored
flag to true:There is no access control check here to restrict who can call this. The impact is that anyone can trigger the rate storage after expiry. This could be used by an attacker to manipulate the rates stored if the actual market rates have moved significantly. For example, an attacker could:
storeRatesAtExpiry()
with the old rates if rates have dropped a lotTools Used
Manual
Recommended Mitigation Steps
The
storeRatesAtExpiry()
function should be restricted to an authorized role, for example:This would prevent unauthorized actors from manipulating the stored rates.
Assessed type
Other