GivingThanks

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

Self-donation by malicious charity leads to unlimited NFT minting

Summary

The donate function in the GivingThanks contract allows a verified charity address to receive Ether and mints an NFT for the donor. However, a malicious charity could exploit this setup by sending donations to itself, minting multiple NFTs without actually contributing funds from an external source.

Vulnerability Details

The vulnerability lies in the donate function:

function donate(address charity) public payable {
require(registry.isVerified(charity), "Charity not verified");
(bool sent,) = charity.call{value: msg.value}("");
require(sent, "Failed to send Ether");
_mint(msg.sender, tokenCounter);
// Create metadata for the tokenURI
string memory uri = _createTokenURI(msg.sender, block.timestamp, msg.value);
_setTokenURI(tokenCounter, uri);
tokenCounter += 1;
}

Since any address listed in the CharityRegistry can receive donations and trigger NFT minting, a malicious charity could make a self-donation to mint NFTs without real external contributions. This could result in the issuance of multiple NFTs without genuine donations, as the donate function does not verify if the donor address is distinct from the charity address.

Impact

An attacker can exploit this vulnerability to mint multiple NFTs for themselves by simply sending Ether to the contract and marking it as a “donation.” This undermines the protocol’s intent of recognizing true charitable donations and could lead to an inflation of NFTs, which would devalue genuine donations and harm the protocol’s reputation.

Tools Used

Manual Review

Recommended Mitigation

To prevent this issue, add a check to ensure that the msg.sender (donor) and the charity address are distinct. This will ensure that a charity cannot donate to itself to mint NFTs fraudulently:

function donate(address charity) public payable {
require(registry.isVerified(charity), "Charity not verified");
require(msg.sender != charity, "Self-donation is not allowed");
(bool sent,) = charity.call{value: msg.value}("");
require(sent, "Failed to send Ether");
_mint(msg.sender, tokenCounter);
string memory uri = _createTokenURI(msg.sender, block.timestamp, msg.value);
_setTokenURI(tokenCounter, uri);
tokenCounter += 1;
}

This check will block any self-donations by a charity, preserving the integrity of the donation process and NFT issuance.

Updates

Lead Judging Commences

n0kto Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Appeal created

dod4ufn Submitter
about 1 year ago
n0kto Lead Judge
12 months ago
n0kto Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

finding-charities-can-get-big-amount-NFT-for-free

Likelyhood: Informational/Very low, admin will verified the contract. Impact: High, NFT with real value for free. I accept this one has a Low due to its High Impact.

Support

FAQs

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