The InheritanceManager.sol contract has a critical flaw in its inherit function. After a 90-day inactivity period, if there is exactly one beneficiary, any address can call inherit() and become the new owner of the contract. There’s no check to verify that the caller (msg.sender) is the listed beneficiary, allowing an attacker to hijack the contract and gain full control over its assets and functions.
File: InheritanceManager.sol
Function: inherit()
An attacker can take ownership of the contract, accessing all funds (e.g., ETH, tokens), NFTs, and administrative privileges.
How the Exploit Works
The inherit function is designed to transfer ownership after 90 days of owner inactivity. When there’s one beneficiary, it simply sets owner = msg.sender without verifying the caller’s identity. An attacker can exploit this by waiting out the 90-day period and calling the function from any address.
Step-by-Step Exploit Execution
Setup:
The contract is deployed with an owner and one beneficiary (beneficiary1).
The owner adds beneficiary1 using addBeneficiery() (note: likely a typo for addBeneficiary).
The owner stops interacting with the contract, triggering the 90-day countdown.
Waiting Period:
Time advances past 90 days (e.g., using vm.warp in testing or real-world time).
Exploit:
An attacker, using an unrelated address (e.g., attacker), calls inherit().
Since beneficiaries.length == 1, the function executes owner = msg.sender, making attacker the new owner.
Result:
The attacker now owns the contract and can:
Withdraw all ETH and tokens.
Manage NFTs (e.g., burn or transfer via NFTFactory).
Add or remove beneficiaries at will.
my own vuln scanner, AI and foundry
Proof of Concept (PoC)
Modify the inherit function to restrict ownership transfer to the designated beneficiary when there is only one beneficiary:
Explanation
Change: Added if (msg.sender != beneficiaries[0]) revert NotBeneficiary(msg.sender); to ensure only the beneficiary can claim ownership.
Why It Works: This check prevents unauthorized callers from taking over the contract, aligning the function with its intended purpose.
Best Practice: Always validate caller permissions in functions that modify critical state, such as ownership.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.