Closed sherlock-admin closed 1 year ago
This is true, but not enough of a concern to warrant making changes. badStandings
is a primitive to enable penalties and other forms of accountability, so we don't want to put everybody in bad standing by default, and reverting all failed calls to eligibility modules would break humanistic eligibility behavior (ie those that make calls to setHatWearerStatus
).
This does mean that admins are responsible for diligently setting robust eligibility modules, but that's the case generally and not just because of this specific risk.
I recommend setting this as a low severity, and will likely not address in fixes.
clems4ever
medium
False default value for badStanding can expose the hat to side effects.
Summary
While, checking whether a wearer is eligible, if the call to the
getWearerStatus
function of the eligibility module set by the admin fails (reverting or does not return proper data), then there is a fallback mechanism that checks the value stored inbadStandings
mapping to determine whether a wearer is eligible. However, the default value for all values inbadStandings
is false and by implementing a fallback mechanism based on badStandings withfalse
as a default value, this raises the risk of an attack exploiting the eligibility module and having side effects on the hat.In a nutshell, if an attacker can try to find any way possible for the call to the eligibility module fail, then leveraging the current code she can force a read of
badStandings
for the given wearer but this value is likely not initialized and would return false. Sinceeligibility = !badStandings
, it means that if the attacker finds a way to exploit the eligibility module it can make a previously non-eligible wearer to become eligible again.In the rather non nominal case where the call to eligibility fails, we'd rather be on the safe side and consider everyone to be non eligible.
I can see two possible improvements to prevent this issue:
goodStandings
instead ofbadStandings
. Since the default value for the bool would still be false, any potential wearer would be considered in bad standing by default and therefore a wearer previously tagged as non eligible by the module would remain non eligible at least until manual intervention. If the eligibility module becomes exploited at some point this solution would prevent any side effect on the hat.Vulnerability Detail
A user can wear a hat if he or she is eligible. This is checked by looking at the balance of the given hat in
However,
_isEligible
calls the eligibility module in order to compute whether a wearer is eligible and in the case this call fails (reverts or send unexpected data), then there is a fallback mechanism used to determine whether the wearer is eligible as we can read in the function below.Now, let say Bob was wearing a hat and is considered non eligible anymore by the rules of the eligibility contracts but this contracts gets broken by an attack, then the attacker can force execution of the last branch of this function which would consider the wearer eligible while it is not anymore regarding the eligibility rules defined in the eligibility contract.
Impact
An exploit to an eligibility module can have side effect on the hat and consider a non-eligible wearer to still be eligible.
Code Snippet
https://github.com/Hats-Protocol/hats-protocol/blob/fafcfdf046c0369c1f9e077eacd94a328f9d7af0/src/Hats.sol#L996
Tool used
Manual Review
Recommendation
goodStandings
instead ofbadStandings
. This mapping would consider everyone to be in bad standing state by default. If the eligibility module ends up in a non-nominal state at some point this solution would at least ensure that if no default value has been set for this wearer, he or she does not wrongly get considered eligible while it should not.