Details:
The withdrawInheritedFunds
function (lines 179–201) is documented as being callable by beneficiaries to disperse remaining assets. However, the implementation does not restrict the caller – anyone can call this function once isInherited
is set to true. This discrepancy between the documented intent and the actual access control could lead to unanticipated behavior.
Root Cause:
The function lacks an access control check (e.g., a modifier that verifies msg.sender
is one of the beneficiaries). As a result, the function does not enforce the intended restriction to only allow beneficiaries to trigger the withdrawal process.
Impact:
While the function distributes funds to beneficiaries regardless of who calls it, allowing any actor to trigger the withdrawal may disrupt the planned timing and process of asset distribution. An attacker or any arbitrary user could force the withdrawal at an inopportune moment, potentially interfering with proper inheritance management or creating denial-of-service conditions by repeatedly triggering the function.
Recommendation:
Restrict access to the withdrawInheritedFunds
function by adding a modifier that verifies the caller is one of the beneficiaries. For example, implement and apply an onlyBeneficiary
modifier that checks if msg.sender
is included in the beneficiaries array before proceeding with the withdrawal logic.
Proof of Concept:
Set up the contract such that isInherited
is set to true
(e.g., by calling the inherit()
function under the proper conditions).
From an account that is not listed as a beneficiary, call withdrawInheritedFunds
with a valid asset address (or address(0)
for ETH).
Observe that the function executes successfully and distributes available funds among the beneficiaries, despite the caller not being a beneficiary.
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.