Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: medium
Likelihood: low
Invalid

Missing Zero Address Check in ETH Transfers

Description

The _payout function does not check if the recipient address is the zero address (0x0) before transferring ETH, which could lead to permanent loss of funds.

Expected Behavior

The function should validate that the recipient address is not the zero address before attempting to transfer ETH.

Actual Behavior

The function transfers ETH to any address provided, including the zero address, which would result in the funds being permanently lost.

Root Cause

The function lacks a validation check for the zero address:

function _payout(address recipient, uint256 amount) internal {
if (amount == 0) return;
(bool success, ) = payable(recipient).call{value: amount}("");
if (!success) {
failedTransferCredits[recipient] += amount;
}
}

Risk Assessment

Impact

If ETH is sent to the zero address, the funds will be permanently lost, resulting in financial loss for the protocol or its users.

Likelihood

The likelihood is low because it would typically require a programming error or deliberate action to pass the zero address as a recipient.

Proof of Concept

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/BidBeastsNFTMarketPlace.sol";
import "../src/BidBeasts_NFT_ERC721.sol";
contract ExploitTest is Test {
BidBeastsNFTMarket market;
BidBeasts nft;
function setUp() public {
// Deploy contracts
nft = new BidBeasts();
market = new BidBeastsNFTMarket(address(nft));
// Fund the market contract
vm.deal(address(market), 1 ether);
}
function testZeroAddressPayout() public {
// Initial state
uint256 initialBalance = address(market).balance;
console.log("Initial market balance:", initialBalance);
// Call _payout with zero address (this would be an internal call in practice)
vm.prank(address(market));
market.exposed_payout(address(0), 1 ether);
// Verification
console.log("Market balance after:", address(market).balance);
assertEq(address(market).balance, initialBalance - 1 ether, "Funds were sent to zero address");
// The funds are now permanently lost
}
}
// For testing purposes, we'd need to expose the internal function
contract ExposedMarket is BidBeastsNFTMarket {
constructor(address _nft) BidBeastsNFTMarket(_nft) {}
function exposed_payout(address recipient, uint256 amount) public {
_payout(recipient, amount);
}
}

Recommended Mitigation

Add a zero address check to the _payout function:

// Before: Vulnerable code
function _payout(address recipient, uint256 amount) internal {
if (amount == 0) return;
(bool success, ) = payable(recipient).call{value: amount}("");
if (!success) {
failedTransferCredits[recipient] += amount;
}
}
// After: Fixed code
function _payout(address recipient, uint256 amount) internal {
if (amount == 0) return;
require(recipient != address(0), "Cannot send to zero address");
(bool success, ) = payable(recipient).call{value: amount}("");
if (!success) {
failedTransferCredits[recipient] += amount;
}
}

Explanation

The fixed implementation adds a check to ensure that the recipient address is not the zero address, preventing accidental loss of funds.

Updates

Lead Judging Commences

cryptoghost Lead Judge 2 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.

Give us feedback!