Description:
The _getBeneficiaryIndex() function returns 0 when the given address is not found in the beneficiaries array. However, it also correctly returns 0 when the first beneficiary is actually present. This leads to a dangerous edge case in InheritanceManager::removeBeneficiary():
If _getBeneficiaryIndex() returns 0 because the given address is not in the array, the function wrongly deletes the beneficiary at slot 0.
This can result in unintended loss of a valid beneficiary.
Funds Loss: If slot 0 is deleted, future fund transfers might be sent to address(0), effectively burning funds.
DoS Vulnerability: In case of ERC-20 transfers, sending to address(0) triggers an ERC20InvalidReceiver error, reverting the entire transaction. This means that no other beneficiaries will receive funds, causing a denial of service (DoS).
Impact:
High Severity
Likelihood: High – If a non-existent address is provided, the first beneficiary is always deleted.
Loss of Beneficiary: A valid beneficiary could be wrongfully removed.
Funds Loss: If slot 0 is deleted, future ETH or ERC-20 transfers may be sent to address(0), effectively burning funds.
DoS Attack: If ERC-20 transfers are attempted to address(0), the transaction will revert due to ERC20InvalidReceiver error, preventing all other beneficiaries from receiving funds.
Proof of Concept
Logs: InheritanceManager::withdrawInheritedFunds(0x0000000000000000000000000000000000000000)
@> [0] 0x0000000000000000000000000000000000000000::fallback{value: 2500000000000000000}() //burning funds
[Stop]
[0] user2::fallback{value: 2500000000000000000}()
[Stop]
[0] user3::fallback{value: 2500000000000000000}()
[Stop]
[0] user4::fallback{value: 2500000000000000000}()
[Stop]
Logs: InheritanceManager::buyOutEstateNFT(1)
ERC20Mock::transfer(0x0000000000000000000000000000000000000000, 187500 [1.875e5])
[Revert] ERC20InvalidReceiver(0x0000000000000000000000000000000000000000)
Recommended Mitigation:
To fix this issue, _getBeneficiaryIndex() should explicitly return an invalid index (e.g., type(uint256).max) when the address is not found. removeBeneficiary() should then check if the returned index is valid before deleting:
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.