GivingThanks

First Flight #28
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Invalid

Lack of Address Validation for Recipient in donate Function, Potential for Misaddressed Transfers

Summary

The donate function in the GivingThanks contract sends Ether to the specified charity address without any checks to confirm that the address corresponds to the intended recipient. While registry.isVerified confirms the address is listed as verified, there is no mechanism to ensure that the donor (msg.sender) intended to send funds specifically to the charity address provided, leading to the risk of accidental or unintended transfers.

Vulnerability Details

When donate is called, the contract verifies that the charity address is valid and registered. However, there is no check to confirm the donor’s intent regarding the specific charity address, leaving room for errors if the donor accidentally inputs the wrong address or is subject to a phishing attack. Since the function directly executes the transfer with (bool sent,) = charity.call{value: msg.value}("");, this lack of additional validation can lead to unintended fund misdirection.

Impact

Without confirming the donor’s intent to send funds to the specific address, donors may accidentally transfer funds to unintended recipients, resulting in permanent loss of donations and decreasing trust in the security and reliability of the contract.

Tools Used

  • Manual Code Review

  • Foundry

Recommendations

Consider introducing checks fo

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract GivingThanks is ERC721URIStorage, Ownable {
mapping(address => address) public donationIntent;
CharityRegistry public registry;
uint256 public tokenCounter;
constructor(address _registry) ERC721("DonationReceipt", "DRC") {
registry = CharityRegistry(_registry);
tokenCounter = 0;
}
// Step 1: Donor sets their donation intent to a specific charity address
function setDonationIntent(address charity) external {
require(charity != address(0), "Invalid charity address");
require(registry.isVerified(charity), "Charity not verified");
// Set the intended charity address for msg.sender
donationIntent[msg.sender] = charity;
}
// Step 2: Donor confirms donation intent by calling donate
function donate() external payable {
address charity = donationIntent[msg.sender];
// Ensure that msg.sender has set an intended charity address
require(charity != address(0), "No donation intent set");
require(msg.value > 0, "Donation amount must be greater than zero");
// Transfer the funds to the intended charity
(bool sent, ) = charity.call{value: msg.value}("");
require(sent, "Failed to send Ether");
// Mint NFT and set token URI
_mint(msg.sender, tokenCounter);
string memory uri = _createTokenURI(msg.sender, block.timestamp, msg.value);
_setTokenURI(tokenCounter, uri);
// Increment tokenCounter and clear donation intent
tokenCounter += 1;
delete donationIntent[msg.sender];
}
// Code...
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.