Open code423n4 opened 1 year ago
MikeHathaway marked the issue as sponsor confirmed
Picodes marked the issue as satisfactory
Picodes marked the issue as primary issue
Picodes marked the issue as selected for report
Picodes changed the severity to 2 (Med Risk)
Giving Medium severity for "Assets not at direct risk, but the function of the protocol or its availability could be impacted"
Hi, @Picodes
I would like to ask you to reconsider the severity of the issue. You've classified it as Med
- Assets not at direct risk, but the function of the protocol or its availability could be impacted
.
Upon review, in my opinion, this issue leans more towards HIGH - Assets can be stolen/lost/compromised directly (or indirectly if there is a valid attack path that does not have hand-wavy hypotheticals)
.
Below, I will attempt to present my reasoning and why I think this way:
I've considered 2
metrics to determine severity:
And came up with the following results:
Consequences
The consequence of this issue is that in the event of it happening, NFTs are blocked on the RewardsManager.sol contract with no possibility of their further withdrawal. This is critical and falls under: Assets can be stolen/lost/compromised directly
. Moreover, these are not just NFTs, they are LP positions.
When this problem occurs, the ability for stake/unstake/claimRewards
of the affected pools is closed due to a mathematical error, leading to a simple blockage of interaction with these pools. As it becomes impossible to process the reward update for a given epoch. For pools that weren't affected and managed to process before, they will be able to operate further until the situation repeats.
The main point in deciding whether it's Medium/High
is how likely this problem is to occur.
Here I looked at the dependence in calculations on the number of pools
uint256 rewardsCapped = Maths.wmul(REWARD_CAP, totalBurnedInPeriod);
// Check rewards claimed - check that less than 80% of the tokens for a given burn event have been claimed.
if (rewardsClaimedInEpoch_ + newRewards_ > rewardsCapped) {
// set claim reward to difference between cap and reward
newRewards_ = rewardsCapped - rewardsClaimedInEpoch_;
}
rewardsClaimedInEpoch_
is a value that sums up across all pools
rewardsCapped
is a value related to the calculation of a single pool and depends on the number of coins burned in the epoch in the selected pool
And there arises a situation when n1 - (n2 + n3...+ nn)
by pools. In reality, it's all more complex and depends on the number of burned coins in the pools, but the essence is that the more pools we have, the higher the chances that this condition simply reverts. And this is no longer an unlikely situation.
Also an example of a highly probable situation:
When there's a HUGE pool and several small ones in the middle. It's enough for only the HUGE pool to update the epoch's reward. This will cause a problem with the condition's execution for all other small pools
This can also be a vector of an attacker who purposely burns an extra amount of coins to increase the reward update on the pool. And causes positions blocking in the contract.
After these considerations, I would like you to reconsider the severity of the problem, as we have two points:
I hope my thoughts will be useful, I understand that I can be wrong and I hope you can clarify if I am not understanding something correctly
Thank you,
Hi, @BhHaipls thanks for your comment. Upon review I agree with your take and will upgrade to High.
Picodes changed the severity to 3 (High Risk)
Lines of code
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/RewardsManager.sol#L549 https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/RewardsManager.sol#L725
Vulnerability details
Impact
RewardsManage.sol
keeps track of the total number of rewards collected per epoch for all pools:And the
rewardsCap
calculation when calculating the reward applies only to the pool, which leads to a situation when the condition is fulfilledrewardsClaimedInEpoch + updatedRewards_ >= rewardsCap
, ButrewardsCap
is less thanrewardsClaimedInEpoch
:which causes an
underflow
erorr in the resultupdatedRewards_ = rewardsCap - rewardsClaimedInEpoch
whererewardsCap < rewardsClaimedInEpoch
, this error leads to a transaction fail, which will further temporarily/permanently block actions with NFT asunstake/claimRewards
for pools in whichrewardsCap
will fail less than the totalrewardsClaimedInEpoch
We have 2 instances of this problem::
_calculateNewRewards
_updateBucketExchangeRates
a failure in any of these will result in users of certain pools being unable to withdraw their NFTs as well as the reward
Proof of Concept
Let's take a closer look at the problem and why this is possible:
We have a situation where
rewardsClaimedInEpoch_
has been updated by other pools to something like100e18
, andrewardsCapped
for the other pool was30e18
, resulting in:rewardsClaimedInEpoch_ + newRewards_ > rewardsCapped
and of course we catch the underflow at the time of calculating the remainder,30e18 - 100e18
, since there is no remaindernewRewards_ = rewardsCapped - rewardsClaimedInEpoch_
To check the problem, you need to raise
rewardsClaimedInEpoch_
more than therewardsCap
of a certain pool, with the help of other pools,rewardsCap
is a percentage of burned tokens in the pool... so it's possibleTools Used
Recommended Mitigation Steps
rewardsClaimedInEpoch > rewardsCap
thatupdatedRewards_
should be zero, not need calculate remaining differenceAssessed type
Invalid Validation