Root Cause: Unbounded iteration over beneficiaries; Impact: Denial of service preventing withdrawals
The contract’s withdrawal functions iterate over the entire beneficiaries array to distribute funds or assets. With an excessively large beneficiary list, these loops can become too gas intensive, potentially exceeding the block gas limit. This can prevent the execution of withdrawals, locking funds in the contract and effectively causing a denial-of-service (DoS) condition that undermines the inheritance mechanism.
Affected Functions:
withdrawInheritedFunds(address _asset)
Other looping mechanisms (e.g., the beneficiary check in onlyBeneficiaryWithIsInherited
)
Description:
These functions use for loops that iterate over all beneficiaries. If the array grows beyond a moderate size, the gas cost of completing the loop may exceed the block gas limit, causing the transaction to revert. An attacker or misconfiguration (e.g., intentionally adding a very large number of beneficiaries) can trigger this condition, resulting in a DoS that prevents beneficiaries from withdrawing funds.
The vulnerability stems from the design choice to use a loop that processes each beneficiary sequentially without a limit or batching mechanism. This linear scaling means that as the number of beneficiaries increases, so does the gas cost—potentially reaching a point where the function call cannot be executed within the block gas limit.
** Impact:** Beneficiaries may be unable to withdraw their funds, potentially locking significant assets in the contract.
Protocol Stability: The inability to process withdrawals could severely damage user trust and lead to disputes regarding fund accessibility
Below is a Foundry test that simulates the gas exhaustion scenario by adding a large number of beneficiaries and attempting a withdrawal. The test expects the call to revert due to exceeding the gas limit.
** Output:**
When running the test with Foundry (using command forge test --match-contract WithdrawalLoopTest
), output :
This indicates that the test passed because the withdrawal call reverted as expected due to excessive gas consumption caused by the loop iterating over 500 beneficiaries.
Refactor Looping Logic:
Batch Processing: Implement a mechanism to process withdrawals in batches rather than in one go.
Pull Payment Pattern: Instead of looping over all beneficiaries in one transaction, allow each beneficiary to individually withdraw their share (pull payments) from a mapping that tracks their entitlement.
Gas Optimization:
Optimize the loop logic where possible and consider off-chain aggregation of beneficiary actions to reduce on-chain gas consumption.
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.