Open c4-bot-6 opened 6 months ago
0xSorryNotSorry marked the issue as sufficient quality report
0xSorryNotSorry marked the issue as duplicate of #1110
Trumpero marked the issue as satisfactory
Trumpero marked the issue as selected for report
I chose this issue to be the primary issue since it has a clear description and contains a PoC.
Hey @Trumpero, this issue stem from an admin mistake making low based on c4 severity standardization:
Reckless admin mistakes are invalid.
PS: It is very unlikely that the GAUGE_PARAMETERS role will set max gauges to 6500.
Hi @0xbtk,
You misunderstood. The configuration in the deployment script allows the SurplusGuildMinter
contract to subscribe to terms over the maximum gauges setting (unlimited!!).
Please refer to my issue for more details: https://github.com/code-423n4/2023-12-ethereumcreditguild-findings/issues/1110.
@serial-coder I would like to understand a little bit more about this. So, the configuration deployment script allows the SurplusGuildMinter to subscribe to an unlimited number of gauges, but, isn't the admin role the one who has the permissions to subscribe a SurplusGuildMinter to terms?
I think @0xbtk has a point here, if the admin is the only one who can subscribe the SurplusGuildMinter to terms, then, subscribing to such an excessing amount of terms would be an admin mistake, isn't it?
Hi @stalinMacias,
You might have an incorrect assumption. The protocol lets GUILD community voters vote for onboarding lending terms. Specifically, the GUILD holders can vote to onboard and register lending terms to the SurplusGuildMinter
contract through the LendingTermOnboarding::proposeOnboard()
.
This is not specific to protocol admins. As long as the term receives a sufficient voting quorum, it will be registered to the SurplusGuildMinter
contract.
@serial-coder But also, the GUILD community voters have the incentive to vote against onboarding a lending term that is not beneficial for them, right? So, what is the incentive for a "malicious user" or "malicious voter" to max out the number of terms that a SuplusGuildMinter can have? Considering they need to pay gas for all those transactions, plus, they need to put down PeggedTokens so they can earn CreditTokens to eventually earn GUILD tokens as rewards?
Looks quite unlikely imo. If we look at the uniswapV2 factory contract, we see there was only ever 1956 pair deployments on a permissionless free-for-all contract. Expecting a semi-permissioned system to hit 6k+ is extremely unrealistic. OOG errors should only be valid if there is a straight-forward way to trigger them. While the impact is high, the likelihood is extremely low, and should be downgraded.
I understand that the likelihood of this issue occurring is very low, but there is no evidence to prove that it cannot happen in the future. The PoC test used 6500 terms, but they didn't transfer any rewards. Therefore, the number of terms needed to exceed the block gas limit in a real case is much lower, as transferring tokens will consume a significant amount of gas. The protocol might have a large number of active lending terms across multiple markets in the future, so there is no guarantee that this number is always safe. This vulnerability has a significant impact, which will cause losses to mitigate, so I believe medium severity is appropriate. Additionally, sponsor didn't dispute its severity.
Lines of code
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/SurplusGuildMinter.sol#L239
Vulnerability details
Impact
The
SurplusGuildMinter.getReward()
function invokesProfitManager.claimRewards()
that in a loop claims reward through all gauges/terms forSurplusGuildMinter
as follows.Whereas
SurplusGuildMinter
works with all gauges, and there is no upper limit for theGuildToken.setMaxGauges(max)
, the length of loop could be unbounded.Each call to
stake()
,unstake()
, orgetReward()
ofSurplusGuildMinter
will either consume excessive amount of gas, or revert with Out-Of-Gas reason after certain number of gauges/terms were added.Proof of Concept
SurplusGuildMinter
.stake()
,unstake()
, orgetReward()
, the call reverts due to Out-Of-Gas reason.Run Poc with the following command.
Tools Used
Manual review.
Recommended Mitigation Steps
Inside
SurplusGuildMinter.getReward(user, term)
callinstead of
Since the purpose of
SurplusGuildMinter.getReward(user, term)
is to update the profit index only for a specificterm
, so there is no need to update profit indexes across all available terms.Assessed type
DoS