Skip to content

Latest commit

 

History

History
85 lines (71 loc) · 4.18 KB

File metadata and controls

85 lines (71 loc) · 4.18 KB

Bubbly Porcelain Blackbird

High

The author vouch.balance locked forever

Summary

The profile unable to withdraw their vouch.balance, due to an unexpected check.

Root Cause

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).

Impact

Due to restriction imposed on unvouch(), the profile funds locked forever in the Vouch contract.

PoC

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

Mitigation

Similar to increaseVouch(), allow other addresses of the profile to unvouch() also.