-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Median is not updated when burning a position, which can result in an inaccurate solvency check #540
Comments
Picodes marked the issue as primary issue |
This is a subjective design choice -- no specific security issues arise from not updating the s_miniMedian at burn, or for that matter, any other operation (whether the price is stale or not depends on the specific situation and is up to interpretation -- we discouraged issues regarding stale prices in the contest README). There is a pokeMedian function that allows the median tick to be updated every minute if required. |
Picodes marked the issue as unsatisfactory: |
Minting:
Burning:
If we call If we now call We have two oracle ticks: slow and fast. Usually we check only the fast one, but sometimes we have to check both if one of these is stale.
Security issues: Scenario: User is solvent at fast tick, but the slow tick is stale so we have to check both. But the solvency check uses the Given the previous assumptions, this would permit users to burn their options when they are insolvent, for example.
This is true, but users have zero incentives to call this function themselves (especially for each single pool). The protocol would bear the cost of calling this function for each pool/pair of tokens, constantly, on Mainnet, which has a huge transaction cost; so it seems an unrealistic (or at least very expensive) solution to me. |
"users have zero incentives to call this function themselves" -> but liquidators do in theory "this would permit users to burn their options when they are insolvent" -> so the edge case would be that the user is solvent at the fast tick (so recently), was at the old slow oracle, but isn't under the new median price, in which case it seems that this isn't too much of an issue as the user is solvent under the fast tick, and that the user was insolvent for some time (while the new median was building up) so should have been liquidated? Considering this and all the precautions taken by the sponsor in the readme, QA seems appropriate to me. |
Picodes changed the severity to QA (Quality Assurance) |
Picodes marked the issue as grade-a |
They do, but only if they know about this issue. Otherwise they would assume that the protocol works correctly, and it wouldn't make sense to spend money by calling that function.
The worst case scenario is where both ticks are stale (i.e. the fast is stale, and the old is wrong as the median is not updated), this would let a user burn even if they are currently insolvent, because we are checking the solvency with a stale fast tick (but right now they are insolvent) and checking the backup solvency with the wrong price with the slow tick, and that would not revert. /// @notice Falls back to the more conservative tick if the delta between the fast and slow oracle exceeds `MAX_SLOW_FAST_DELTA`.
/// @dev Effectively, this means that the users must be solvent at both the fast and slow oracle ticks if one of them is stale to mint or burn options. Right now user is insolvent > fast tick stale, but user is solvent > fallback to conservative slow tick > slow tick is wrong and user is solvent there, but with the correct one they would be insolvent > user can burn, but they shouldn't as they are insolvent It's also worth noting that there are consequences if we remove the median calculation from mint:
Suppose that also the minting never updated the median. The slow tick would always be zero, and all users would be considered insolvent, unless someone constantly calls There are some 'ifs', but this issue still seems Medium to me as there is a leak of value given these assumptions:
|
@DadeKuma my understanding is that the fast tick isn't dependant on "Suppose that also the minting never updated the median. The slow tick would always be zero, and all users would be considered insolvent unless someone constantly calls pokeMedian for each pool." -> My understanding is that this is to some extent the required design. You don't need to constantly call |
Tagging @dyedm1 for visibility |
Lines of code
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L569
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L944
Vulnerability details
Impact
Median price is updated when minting, but not burning. This value is used to calculate the solvency of a user and it might be very inaccurate with pools that have sparse minting but frequent burning.
Proof of Concept
burnOptions
doesn't update the median in any of the inner functions:Suppose the following assumptions:
Now suppose that we need to call
_validateSolvency
:A stale
s_miniMedian
is used to calculate theslowOracleTick
if someone has burned their position. The solvency check may pass even if this is no longer the case, as the latter solvency check uses theslowOracleTick
.Tools Used
Manual review
Recommended Mitigation Steps
Consider recalculating the median when a position is burned (and enough time has passed to prevent a price manipulation), similar to the minting logic:
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: