The withdrawInheritedFunds
function in the InheritanceManager
contract is vulnerable to a reentrancy attack when distributing Ether. A malicious beneficiary could exploit this vulnerability to repeatedly withdraw more funds than they are entitled to, potentially draining the contract's Ether balance.
withdrawInheritedFunds
Function:
Purpose: Distributes the contract's Ether or ERC20 token balance equally among the beneficiaries.
Logic:
Checks if the contract has been inherited (isInherited
).
Calculates the amount each beneficiary should receive (amountPerBeneficiary
).
Iterates through the beneficiaries
array.
If distributing Ether, it uses beneficiary.call{value: amountPerBeneficiary}("")
to send Ether.
If distributing an ERC20 token, it uses safeTransfer
to send tokens.
Vulnerability: The use of .call{value: ...}("")
to send Ether opens up a reentrancy attack vector.
No nonReentrant
: The function does not use nonReentrant
to protect itself from reentrant calls.
Code:
Reentrancy Exploit:
Malicious Beneficiary: A malicious beneficiary can create a contract that implements a fallback or receive function.
Fallback/Receive Trigger: When the withdrawInheritedFunds
function calls the malicious beneficiary's contract with .call{value: ...}("")
, the fallback or receive function in the malicious contract is triggered.
Reentrant Call: Within the fallback or receive function, the malicious contract can call back into withdrawInheritedFunds
again before the original execution of withdrawInheritedFunds
has completed.
Repeated Withdrawals: Because the first call hasn't finished, the malicious contract can receive eth again, draining more funds than it is allowed.
Loss of Funds: The most severe impact is the potential for the malicious beneficiary to drain a significant portion or even all of the contract's Ether.
Unfair Distribution: Even if the contract isn't fully drained, the intended equal distribution among beneficiaries will be disrupted, with the malicious beneficiary receiving more than their fair share.
Manual Code Review
Use nonReentrant
Modifier: The simplest and most effective solution is to apply the nonReentrant
modifier from Openzeppelin's ReentrancyGuard library to the withdrawInheritedFunds
function. This will prevent reentrant calls.
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.