The donate function in GivingThanks.sol performs a low-level .call to transfer funds to charity, without checking whether the address is associated with a deployed contract. According to the Solidity documentation, the EVM considers a low-level call to a non-existing contract to not revert but instead return true, even though the funds may be sent to an invalid address. This can lead to donations being lost or misdirected if the charity address is not properly validated.
The donate function uses a low-level call to transfer Ether:
According to the Solidity documentation, when using low-level calls, the EVM does not automatically verify that the target address is associated with a contract. This can lead to silent failures where calls to non-existing contracts succeed even though no code exists at the target address. Normally, Solidity uses extcodesize to ensure the called address has code, but this check is bypassed when using low-level calls. Here, function donate() checks mapping registeredCharities[charity] by calling function isVerified() in CharityRegistry.sol, which does not guarantee the presence of an actual deployed contract.
Solidity Documentation Reference:External Function Calls
In this context, low-level calls bypass this validation, meaning that donations could be sent to non-existing address.
Loss of Funds: If a non-existing contract charity address is used, funds may be sent to an unintended address without error, leading to permanent loss.
Solidity documentation and manual code review.
If charity is not an Externally Owned Address implement contract existence checks before transferring funds, use Solidity’s Address.isContract function from the OpenZeppelin library (or a similar method) to verify that the charity address has deployed code.
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.