the protocol has the levels for admins and it starts from 0 to 15
function getLocalHatLevel(uint256 _hatId) public pure returns (uint32 level) {
if (_hatId & uint256(type(uint224).max) == 0) return 0;
if (_hatId & uint256(type(uint208).max) == 0) return 1;
if (_hatId & uint256(type(uint192).max) == 0) return 2;
if (_hatId & uint256(type(uint176).max) == 0) return 3;
if (_hatId & uint256(type(uint160).max) == 0) return 4;
if (_hatId & uint256(type(uint144).max) == 0) return 5;
if (_hatId & uint256(type(uint128).max) == 0) return 6;
if (_hatId & uint256(type(uint112).max) == 0) return 7;
if (_hatId & uint256(type(uint96).max) == 0) return 8;
if (_hatId & uint256(type(uint80).max) == 0) return 9;
if (_hatId & uint256(type(uint64).max) == 0) return 10;
if (_hatId & uint256(type(uint48).max) == 0) return 11;
if (_hatId & uint256(type(uint32).max) == 0) return 12;
if (_hatId & uint256(type(uint16).max) == 0) return 13;
return 14;
}
but in the function isAdminOfHat it actually has else part for who is not Tophat
and it getting those hat wearers levels
} else {
// if we get here, _hatId is not a tophat of any kind
// get the local tree level of _hatId's admin
adminLocalHatLevel = getLocalHatLevel(_hatId) - 1;
}
but it decreases -1 and it will cause error on admin level 0 therefore admin level 0 is actually means nothing and its useless at all after this happens all time
Impact
will cause an error on admin level 0 therefore admin level 0 is actually means nothing and its useless at all after this happening all time
Code Snippet
function isAdminOfHat(address _user, uint256 _hatId) public view returns (bool isAdmin) {
uint256 linkedTreeAdmin;
uint32 adminLocalHatLevel;
if (isLocalTopHat(_hatId)) {
linkedTreeAdmin = linkedTreeAdmins[getTopHatDomain(_hatId)];
if (linkedTreeAdmin == 0) {
// tree is not linked
return isAdmin = isWearerOfHat(_user, _hatId);
} else {
// tree is linked
if (isWearerOfHat(_user, linkedTreeAdmin)) {
return isAdmin = true;
} // user wears the treeAdmin
else {
adminLocalHatLevel = getLocalHatLevel(linkedTreeAdmin);
_hatId = linkedTreeAdmin;
}
}
} else {
// if we get here, _hatId is not a tophat of any kind
// get the local tree level of _hatId's admin
adminLocalHatLevel = getLocalHatLevel(_hatId) - 1;
}
// search up _hatId's local address space for an admin hat that the _user wears
while (adminLocalHatLevel > 0) {
if (isWearerOfHat(_user, getAdminAtLocalLevel(_hatId, adminLocalHatLevel))) {
return isAdmin = true;
}
// should not underflow given stopping condition > 0
unchecked {
--adminLocalHatLevel;
}
}
// if we get here, we've reached the top of _hatId's local tree, ie the local tophat
// check if the user wears the local tophat
if (isWearerOfHat(_user, getAdminAtLocalLevel(_hatId, 0))) return isAdmin = true;
// if not, we check if it's linked to another tree
linkedTreeAdmin = linkedTreeAdmins[getTopHatDomain(_hatId)];
if (linkedTreeAdmin == 0) {
// tree is not linked
// we've already learned that user doesn't wear the local tophat, so there's nothing else to check; we return false
return isAdmin = false;
} else {
// tree is linked
// check if user is wearer of linkedTreeAdmin
if (isWearerOfHat(_user, linkedTreeAdmin)) return true;
// if not, recurse to traverse the parent tree for a hat that the user wears
isAdmin = isAdminOfHat(_user, linkedTreeAdmin);
}
}
Avci
high
admin in level 0 is locked and impossible to use
Summary
admin in level 0 is locked and impossible to use
Vulnerability Detail
the protocol has the levels for admins and it starts from
0 to 15
but in the function isAdminOfHat it actually has else part for who is not Tophat
and it getting those hat wearers levels
but it decreases -1 and it will cause error on admin level 0 therefore admin level 0 is actually means nothing and its useless at all after this happens all time
Impact
will cause an error on admin level 0 therefore admin level 0 is actually means nothing and its useless at all after this happening all time
Code Snippet
https://github.com/Hats-Protocol/hats-protocol/blob/fafcfdf046c0369c1f9e077eacd94a328f9d7af0/src/Hats.sol#L852
Tool used
Manual Review
Recommendation
consider modifying contract to the way that admins should start at 1 level by default
Duplicate of #131