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

Missing Deadline Update in `removeBeneficiary` and other functions

Summary

The removeBeneficiary function doesn't update the inactivity deadline, potentially allowing premature inheritance.

Vulnerability Details

Affected Code - https://github.com/CodeHawks-Contests/2025-03-inheritable-smart-contract-wallet/blob/main/src/InheritanceManager.sol#L163-L166

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

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

function removeBeneficiary(address _beneficiary) external onlyOwner {
uint256 indexToRemove = _getBeneficiaryIndex(_beneficiary);
delete beneficiaries[indexToRemove];
// Missing: _setDeadline();
}

Unlike most owner functions, removeBeneficiary doesn't call _setDeadline(), Which breaks the core invariant as per specified in readme.

  1. EVERY transaction the owner does with this contract must reset the 90 days timer

This inconsistent behavior means the inactivity timer isn't reset when removing beneficiaries.

This function has another issue too, submitted in another finding in detail

other affected functions are contractInteractions and createEstateNFT

POC

Add following test to existing test -

function testDeadlineIsNotUpdatedWithEveryOwnerAction() public {
// Add beneficiary and check deadline
vm.prank(owner);
im.addBeneficiery(user1);
uint256 afterAdd = im.getDeadline();
// Time passes
vm.warp(block.timestamp + 30 days);
// Remove beneficiary - isn't updates deadline but should
uint256 beforeRemove = im.getDeadline();
vm.prank(owner);
im.removeBeneficiary(user1);
uint256 afterRemove = im.getDeadline();
// Verify deadline didn't change
assertEq(
beforeRemove,
afterRemove,
"Deadline shouldn't change but should"
);
console.log("Deadline after add:", afterAdd);
console.log("Deadline after remove:", afterRemove);
}

when running forge test --mt testDeadlineIsNotUpdatedWithEveryOwnerAction -vv we get following output, which confirms our finding.

Ran 1 test for test/InheritanceManagerTest.t.sol:InheritanceManagerTest
[PASS] testDeadlineIsNotUpdatedWithEveryOwnerAction() (gas: 75017)
Logs:
Deadline after add: 7776001
Deadline after remove: 7776001
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.45ms (1.11ms CPU time)
Ran 1 test suite in 161.34ms (7.45ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Impact

This inconsistency could lead to premature inheritance if an owner removes beneficiaries and then becomes inactive for a period shorter than the intended timelock.

Tools Used

Foundry

Recommendations

update the functions like this to fix the issue

function removeBeneficiary(address _beneficiary) external onlyOwner {
uint256 indexToRemove = _getBeneficiaryIndex(_beneficiary);
// Use the swap and pop pattern (as suggested in other finding)
beneficiaries[indexToRemove] = beneficiaries[beneficiaries.length - 1];
beneficiaries.pop();
// Reset the inactivity timer
_setDeadline();
}
function contractInteractions(address _target, bytes calldata _payload, uint256 _value, bool _storeTarget)
external
nonReentrant
onlyOwner
{
(bool success, bytes memory data) = _target.call{value: _value}(_payload);
require(success, "interaction failed");
if (_storeTarget) {
interactions[_target] = data;
}
_setDeadline();
}
function createEstateNFT(string memory _description, uint256 _value, address _asset) external onlyOwner {
uint256 nftID = nft.createEstate(_description);
nftValue[nftID] = _value;
assetToPay = _asset;
_setDeadline();
}
Updates

Lead Judging Commences

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

functions do not reset the deadline

Support

FAQs

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