Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Invalid

Critical Unilateral Trustee Appointment Vulnerability

Description

The InheritanceManager contract allows any single beneficiary to appoint a trustee after inheritance is triggered, with no consensus mechanism or restrictions. The trustee then gains significant privileges that can be abused to manipulate NFT values and payment methods, potentially allowing beneficiaries to acquire valuable assets at negligible costs.

The vulnerability exists in the interaction between these functions:

// From InheritanceManager.sol
function appointTrustee(address _trustee) external onlyBeneficiaryWithIsInherited {
trustee = _trustee;
}
// From Trustee.sol
function setNftValue(uint256 _index, uint256 _value) public onlyTrustee {
nftValue[_index] = _value;
}
function setAssetToPay(address _asset) external onlyTrustee {
assetToPay = _asset;
}

Impact

This vulnerability has critical security implications:

  1. Asset Value Manipulation: Any single beneficiary can appoint a trustee who can then arbitrarily devalue estate NFTs.

  2. Payment Asset Substitution: The trustee can set any token (including worthless ones they control) as the payment asset.

  3. Theft of Valuable Assets: After manipulating values and payment methods, beneficiaries can buy out valuable assets for negligible amounts.

  4. Undermined Inheritance System: The entire inheritance distribution system is compromised as consensus among beneficiaries is bypassed.

Attack Scenario

  1. After inheritance is triggered, a malicious beneficiary calls appointTrustee() to set a trustee they control

  2. The trustee calls setNftValue() to reduce the value of NFTs to near zero

  3. The trustee calls setAssetToPay() to set a worthless token as payment method

  4. The beneficiary calls buyOutEstateNFT() to acquire valuable assets for almost nothing, depriving other beneficiaries of their fair share

Recommendation

Implement one or more of the following security measures:

  1. Multi-signature requirement: Require a majority or unanimous agreement from all beneficiaries to appoint a trustee:

mapping(address => bool) public hasApprovedTrustee;
address public proposedTrustee;
uint256 public requiredApprovals;
function proposeTrustee(address _trustee) external onlyBeneficiaryWithIsInherited {
proposedTrustee = _trustee;
delete hasApprovedTrustee;
hasApprovedTrustee[msg.sender] = true;
requiredApprovals = (beneficiaries.length / 2) + 1; // Majority
}
function approveTrustee() external onlyBeneficiaryWithIsInherited {
hasApprovedTrustee[msg.sender] = true;
if(countApprovals() >= requiredApprovals) {
trustee = proposedTrustee;
}
}
  1. Time-lock mechanism: Add a delay between trustee appointment and their ability to change values:

uint256 public trusteeActivationTime;
uint256 public constant TRUSTEE_TIMELOCK = 7 days;
function appointTrustee(address _trustee) external onlyBeneficiaryWithIsInherited {
trustee = _trustee;
trusteeActivationTime = block.timestamp + TRUSTEE_TIMELOCK;
}
modifier onlyActiveTrustee() {
if (msg.sender != trustee || block.timestamp < trusteeActivationTime) {
revert TrusteeNotActiveYet();
}
_;
}

Tools Used

  • Manual Code Review

  • Control Flow Analysis

Updates

Lead Judging Commences

0xtimefliez Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.