The StabilityPool contract is meant to be upgradeable. In case it's going to use the UUPS pattern, it misses a function to authorize upgrades. This means upgrades can be done by anyone as the _authorizeUpgrade() function needs to be overridden with proper access control to only allow trusted accounts to perform an upgrade.
According to the sponsor, the StabilityPool is meant to be an upgradeable contract. Generally, there are two options to make a contract upgradeable:
Using transparent proxies
Using the UUPS pattern
Both options are identical, in the sense that they require a proxy that users will talk to.
However, there's one crucial difference between the two:
When using transparent proxies, the upgrade logic lives in the proxy contract.
When using UUPS, the upgrade logic lives in the logic contract (allowing for upgrading the upgrade logic itself).
Looking at the code, it is unclear which options the implementers of the protocol will use. However, option 2 is more widely adopted these days due to the added flexibility of changing the upgrade logic when upgrading to a newer version.
For this case, the logic contract has to implement and override the necessary function to authorize the upgrades.
This function is missing in StabilityPool resulting in this contract being upgradeable by anyone, if it follows the UUPS pattern.
Due to the missing _authorizeUpgrade function in StabilityPool this contract will be upgradeable by anyone.
Manual review
First of all, add the UUPSUpgradeable to the inheritance chain, this makes it very explicit that this contract is making use of the UUPS pattern. Then, add the necessary _authorizeUpgrade function that this interface expects for its upgradeToAndCall() function.
Ensure that _authorizeUpgrade has proper access control so it can only be called by trusted accounts:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.