Quiet Cyan Hyena
High
When an address is compromised, user delete it from the Ethos profile. However, the deleted address can still perform actions that undeleted addresses are authorized to do.
When an address is compromised, user can delete it from the Ethos profile using the following EthosProfile.deleteAddressAtIndex() function which marks isAddressCompromised
as true
.
The EthosProfile.verifiedProfileIdForAddress function is shown below.
function verifiedProfileIdForAddress(address _address) external view returns (uint256) {
(bool verified, bool archived, bool mock, uint256 profileId) = profileStatusByAddress(_address);
if (!verified || archived || mock) {
revert ProfileNotFoundForAddress(_address);
}
return profileId;
}
... SKIP ...
function profileStatusByAddress(
address addressStr
) public view returns (bool verified, bool archived, bool mock, uint256 profileId) {
profileId = profileIdByAddress[addressStr];
(verified, archived, mock) = profileStatusById(profileId);
}
As can be seen, the function doesn't consider the isAddressCompromised
flag. As a result, even though an address is deleted from a profile, the return value of the verifiedProfileIdForAddress()
function for the deleted address remains unchanged.
The EthosProfile.verifiedProfileIdForAddress()
function is called from many other places of the codebase to authorize the address to perform the following operations:
EthosAttestation.createAttestation()
EthosDiscussion.addReply()
EthosDiscussion.editReply()
EthosReview.addReview()
EthosReview.editReview()
EthosReview.restoreReview()
EthosVote.voteFor()
No response
No response
For example, in the case of the EthosVote.voteFor()
function:
- Address
addr1
is registered toprofile1
. addr1
get compromised and is deleted fromprofile1
by the user.- Even though
addr1
is already deleted, it can still vote for anything by callingEthosVote.voteFor()
.
The vulnerability breaks core contract functionality because a deleted address can still perform actions that undeleted addresses can do.
No response
Modify EthosProfile.verifiedProfileIdForAddress()
function as follows.
- function verifiedProfileIdForAddress(address _address) external view returns (uint256) {
+ function verifiedProfileIdForAddress(address _address) external view checkIfCompromised(_address) returns (uint256) {
(bool verified, bool archived, bool mock, uint256 profileId) = profileStatusByAddress(_address);
if (!verified || archived || mock) {
revert ProfileNotFoundForAddress(_address);
}
return profileId;
}