Bubbly Porcelain Blackbird
High
The profile unable to withdraw their vouch.balance
, due to an unexpected check.
Consider that a profileId
is created and managed by an organization. This profileId
is associated with a list of addresses[]
responsible for managing the profile across the Ethos ecosystem, including the headAddr
(address that created the profile).
addresses= [headAddr, addr1, addr2, addr3]
profileIdByAddress[headAddr] == profileIdByAddress[addr1] == profileIdByAddress[addr2] == profileIdByAddress[addr3] == 10(say) -----------------(1)
The addr2
is actively staking on EthosVouch
contract as an author
to earn rewards(from voucher pool) and to build a strong foundation of trust with other organizations(subjects) on behalf of its organization(author).
Let's say the addr2
vouch for subjectId==5
, the vouches
states updates as
function vouchByProfileId(
uint256 subjectProfileId,
string calldata comment,
string calldata metadata
) public payable whenNotPaused nonReentrant {
...snip...
vouchIdByAuthorForSubjectProfileId[authorProfileId][subjectProfileId] = count;
vouches[count] = Vouch({
archived: false,
unhealthy: false,
authorProfileId: authorProfileId, >> @audit set 10
authorAddress: msg.sender, >> @audit set addr2
vouchId: count,
balance: toDeposit,
subjectProfileId: subjectProfileId, // 5
comment: comment,
metadata: metadata,
activityCheckpoints: ActivityCheckpoints({
vouchedAt: block.timestamp,
unvouchedAt: 0,
unhealthyAt: 0
})
});
emit Vouched(count, authorProfileId, subjectProfileId, msg.value);
vouchCount++;
}
where the vouches[X].authorAddress
is set to addr2
.
The protocol allows other members of the profile, such as headAddr
, addr1
, and addr3
, to call increaseVouch()
on behalf of the organization.
https://github.com/sherlock-audit/2024-11-ethos-network-ii/blob/57c02df7c56f0b18c681a89ebccc28c86c72d8d8/ethos/packages/contracts/contracts/EthosVouch.sol#L426
function increaseVouch(uint256 vouchId) public payable nonReentrant {
// vouch increases much also meet the minimum vouch amount
if (msg.value < configuredMinimumVouchAmount) {
revert MinimumVouchAmount(configuredMinimumVouchAmount);
}
// get the profile id of the author
uint256 profileId = IEthosProfile(
contractAddressManager.getContractAddressForName(ETHOS_PROFILE)
).verifiedProfileIdForAddress(msg.sender); >> @audit due to (1), this will pass
...snip...
However, it restricts the unvouch()
function to addr2
only. If other members attempt to call unvouch()
, the txn reverts due to following check
https://github.com/sherlock-audit/2024-11-ethos-network-ii/blob/57c02df7c56f0b18c681a89ebccc28c86c72d8d8/ethos/packages/contracts/contracts/EthosVouch.sol#L459
if (vouches[vouchId].authorAddress != msg.sender) {
revert AddressNotVouchAuthor(vouchId, msg.sender, vouches[vouchId].authorAddress);
}
this is dangerous, under a condition where the profileAddress(=addr2
) turns to be malignant, the organization(basically the headAddr
) can delete or mark it compromised, thinking other members can unvouch()
it also. This leads the vouch balance to locked forever in EthosVouch
contract(neither the compromised addr2
can withdraw it).
Due to restriction imposed on unvouch()
, the profile funds locked forever in the Vouch
contract.
https://github.com/sherlock-audit/2024-11-ethos-network-ii/blob/57c02df7c56f0b18c681a89ebccc28c86c72d8d8/ethos/packages/contracts/contracts/EthosProfile.sol#L391 https://github.com/sherlock-audit/2024-11-ethos-network-ii/blob/57c02df7c56f0b18c681a89ebccc28c86c72d8d8/ethos/packages/contracts/contracts/EthosVouch.sol#L459-L461
Similar to increaseVouch()
, allow other addresses of the profile to unvouch()
also.