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

Beneficiary can add themselves as Trustee obtaining double-roel and making changes to inheritance disputes

Summary:

The InheritanceManager.sol allows a beneficiary address to also carry the role of trustee which contradicts the protocols implementation as the trustee is supposed to be a 3rd party to settle disputes and/or re-evaluate assets.

Description:

The InheritanceManager.sol::appointTrustee is a function that can only be called by beneficiaries when the contract is in an inheritable state. It sets the "address of appointed trustee for asset reevaluation". However, the function is missing a check whereby a beneficiary cannot also hold a position of trustee. As a result, a beneficiary can set themselves as a trust and re-evaluate assets to their benefit in the event of disputes/disagreements. The function is

function appointTrustee(address _trustee) external onlyBeneficiaryWithIsInherited {//can only be called when funds can be inheritied
trustee = _trustee;
}

This goes against the protocols logic and functioning whereby the trustee is a 3rd party appointed for asset re-evaluation. Furthermore, logically, in a re-evaluation case, the final sayer should not be anyone in/on the persons of interest list.

Impact:

The impact of this is low as the ill-acting beneficiary does not exactly gain extra funds but they do manipulate the payout in a way which may not be agreeable to other beneficiaries.

Tools used:

  • Manual Review

  • Foundry for testing

PoC:

To prove the validity of this issue, I have created a test suite that can be run by: forge test --mt testBenefectoryCanBeTrustee -vvvv

  • 4vs to see the flow of events

The code:

  1. The owner adds 4 beneficiaries and a house worth 2000 ether.

  2. After the 90 day period, the funds are unlocked

  3. A beneficiary tries to call a trustee function but the transaction fails

  4. The beneficiary then sets themselves as a trustee and calls the trustee function again.

  5. The final assertion is to the getTrustee to show that the trustee address and beneficiary address are the same.

function testBenefectoryCanBeTrustee() public{
//Arrange: Handling owner operations
vm.startPrank(owner);
vm.deal(address(im), 100 ether);
console.log("Starting wallet balance: ", address(im).balance);
im.addBeneficiery(benef_1);
im.addBeneficiery(benef_2);
im.addBeneficiery(benef_3);
im.addBeneficiery(benef_4);
string memory description = "This is my house";
uint256 houseValue = 2000 ether;
im.createEstateNFT(description, houseValue, asset);
vm.stopPrank();
vm.warp(1+90 days);
vm.startPrank(benef_1);
im.inherit();
//Act: Benefactory setting themselves up also as trustee : note the caveat, 1 person can hold 2 addresses
vm.startPrank(benef_1);
//calling trustee function proving cannot call
vm.expectRevert();
im.setNftValue(0,500);
//calling trustee function proving they now can
im.appointTrustee(address(benef_1));
im.setNftValue(0,500);
//Assert
assert(im.getTrustee() == address(benef_1));
}

Recommended Mitigation:

The recommended mitigation is to check to make sure the trustee address is also not a beneficiary address.

Updates

Lead Judging Commences

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

Support

FAQs

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