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

Duplicate Beneficiary Vulnerability in InheritanceManager contract

Summary

The InheritanceManager contract is intended to facilitate the equitable distribution of asset such as ETH, ERC20 tokens, and NFT to designated beneficiaries after a predefined period of owner inactivity. However, a significant flaw has been identified: the contract permits the owner to add the same beneficiary multiple times to the beneficiaries array. This oversight leads to an unequal distribution of inheritance shares, as duplicated beneficiaries receive multiple portions of the assets, contradicting the intended equal allocation among unique beneficiaries.

Vulnerability Details

The addBeneficiary function, as currently implemented, allows the owner to append a beneficiary address to the beneficiaries array without verifying whether that address already exists:

function addBeneficiery(address _beneficiary) external onlyOwner {
beneficiaries.push(_beneficiary);
_setDeadline();
}

https://github.com/CodeHawks-Contests/2025-03-inheritable-smart-contract-wallet/blob/9de6350f3b78be35a987e972a1362e26d8d5817d/src/InheritanceManager.sol#L153-L156

Because no uniqueness check is enforced, the same address can appear multiple times in the array. During inheritance distribution (e.g., via a function like withdrawInheritedFunds), the contract calculates shares based on the total number of entries in the beneficiaries array rather than the number of distinct beneficiaries. As a result, a beneficiary listed multiple times receives a share for each entry, skewing the distribution.

Example Scenario

Consider the following case:

Total Inheritance: 100 ETH

Beneficiaries Array: [Alice, Bob, Alice] (Alice appears twice)

Distribution Logic: The contract splits the inheritance into three equal shares (33.33 ETH each).

Result: Alice receives 66.66 ETH (two shares), while Bob receives 33.33 ETH (one share).

This outcome deviates from the intended equal distribution, as Alice inadvertently receives double the share of Bob due to her duplicate entry.

Proof Of concept

function test_duplicateBeneficiaryVulnerability() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
vm.startPrank(owner);
im.addBeneficiery(user1);
im.addBeneficiery(user2);
im.addBeneficiery(user3);
im.addBeneficiery(user1);
vm.deal(address(im), 8e18);
vm.stopPrank();
vm.warp(1 + 90 days);
vm.startPrank(user1);
im.inherit();
im.withdrawInheritedFunds(address(0));
vm.stopPrank();
// assert the user balances
assertEq(4e18, user1.balance);
assertEq(2e18, user2.balance);
assertEq(2e18, user3.balance);
console.log("user1 Bal:", user1.balance);
console.log("user2 Bal:", user2.balance);
console.log("user3 Bal:", user3.balance);
}

Impact

The ability to add duplicate beneficiaries introduces several critical issues:

  • Unequal Distribution: Beneficiaries listed multiple times receive disproportionately larger shares, undermining the fairness of the inheritance process.

  • Potential Disputes: The skewed distribution could spark conflicts or legal challenges among beneficiaries, especially in scenarios involving significant asset values.

  • Owner Error Amplification: An accidental duplicate entry by the owner—a plausible human error—results in substantial financial consequences, reducing the contract’s dependability.

  • Erosion of Trust: The flaw diminishes confidence in the contract’s ability to accurately reflect the owner’s intentions, potentially deterring its use.

Tools Used

Manual Review

Recommendations

  • Implement a Uniqueness Check with a Mapping
    Add a mapping to track existing beneficiaries and prevent duplicates from being added to the beneficiaries array.

mapping(address => bool) private isBeneficiary;
function addBeneficiary(address _beneficiary) external onlyOwner {
require(!isBeneficiary[_beneficiary], "Beneficiary already exists");
beneficiaries.push(_beneficiary);
isBeneficiary[_beneficiary] = true;
_setDeadline();
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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