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

Zero Address Replacement due to use of delete keyword Causing Incorrect Fund Distribution in InheritenceManager.sol

Summary

the use of delete on the beneficiaries array replaces the removed address with the zero address (0x00), causing incorrect inheritance fund distribution.

Vulnerability Details

The removeBeneficiary function uses delete on an array index, which replaces the removed beneficiary with the zero address instead of properly removing the entry. Since the withdrawInheritedFunds function calculates distributions using the array's length, the zero address gets counted in the divisor, leading to incorrect fund division.

Affected Code:

function withdrawInheritedFunds(address _asset) external {
if (!isInherited) {
revert NotYetInherited();
}
uint256 divisor = beneficiaries.length;
if (_asset == address(0)) {
uint256 ethAmountAvailable = address(this).balance;
uint256 amountPerBeneficiary = ethAmountAvailable / divisor;
for (uint256 i = 0; i < divisor; i++) {
address payable beneficiary = payable(beneficiaries[i]);
(bool success,) = beneficiary.call{value: amountPerBeneficiary}("");
require(success, "something went wrong");
}
} else {
uint256 assetAmountAvailable = IERC20(_asset).balanceOf(address(this));
uint256 amountPerBeneficiary = assetAmountAvailable / divisor;
for (uint256 i = 0; i < divisor; i++) {
IERC20(_asset).safeTransfer(beneficiaries[i], amountPerBeneficiary);
}
}
}
function removeBeneficiary(address _beneficiary) external onlyOwner {
uint256 indexToRemove = _getBeneficiaryIndex(_beneficiary);
delete beneficiaries[indexToRemove];
}

Impact

The contract incorrectly divides the total inheritance among all beneficiaries.length entries, including zero addresses.

  • This results in each actual beneficiary receiving less than their intended share.

  • If the removeBeneficiary function is misused, a beneficiary may receive an incorrect inheritance while a zero-address entry consumes a portion of the funds.

Tools Used

Foundry framework for testing

  • Solidity static analysis

  • Manual code review

function test_removingCorrectBeneficiaryCausesUnequalDistribution() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
vm.startPrank(owner);
im.addBeneficiery(user1);
im.addBeneficiery(user2);
im.addBeneficiery(user3);
im.removeBeneficiary(user3);
vm.stopPrank();
im.getBeneficiaries();
vm.warp(1);
vm.deal(address(im), 10e18);
vm.warp(1 + 90 days);
vm.startPrank(user1);
im.inherit();
im.withdrawInheritedFunds(address(0));
vm.stopPrank();
assertEq(0, user3.balance);
assertEq(5e18, user1.balance);
assertEq(5e18, user2.balance);
}
function test_removeBeneficiaryCausesUnequalDistribution() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
address userNotInArray = makeAddr("userNotInArray");
vm.startPrank(owner);
im.addBeneficiery(user1);
im.addBeneficiery(user2);
im.addBeneficiery(user3);
im.removeBeneficiary(userNotInArray);
vm.stopPrank();
im.getBeneficiaries();
vm.warp(1);
vm.deal(address(im), 9e18);
vm.warp(1 + 90 days);
vm.startPrank(user1);
im.inherit();
im.withdrawInheritedFunds(address(0));
vm.stopPrank();
assertEq(3e18, user1.balance);
assertEq(3e18, user2.balance);
assertEq(3e18, user3.balance);
}

Recommendations

Instead of using delete, implement a proper removal mechanism:

function removeBeneficiary(address _beneficiary) external onlyOwner {
uint256 indexToRemove = _getBeneficiaryIndex(_beneficiary);
require(indexToRemove != type(uint256).max, "Beneficiary not found");
// Swap and pop method for efficient array removal
beneficiaries[indexToRemove] = beneficiaries[beneficiaries.length - 1];
beneficiaries.pop();
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge 9 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect removal from beneficiary list causes funds to be send to 0 address

Support

FAQs

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

Give us feedback!