Bid Beasts

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

Reentrancy in _payout function allows attacker to run malicious code on the protocol

Root + Impact

Description

The _payout function directly transfers ETH to the recipient using a low-level call:

`(bool success, ) = payable(recipient).call{value: amount}("");`

Since this transfer happens before updating any accounting state, a malicious recipient contract can implement a fallback function that re-enters the protocol and repeatedly calls functions that eventually trigger _payout, allowing the attacker to withdraw more funds than intended.

Additionally, because state (like marking the payout as processed) is not updated before the external call, the protocol becomes vulnerable to reentrancy attacks.

Risk

Honest bidders risk losing their deposits due to attacker draining balances.

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

Reentracy attack can be done on this function and from there attcker can call other vulnerable function

Impact:

Honest bidders risk losing their deposits due to attacker draining balances.

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

Reentracy attack can be done on this function and from there attcker can call other vulnerable function

Proof of Concept

Attacker places a bid with a malicious contract.

When outbid, _payout is triggered to refund the attacker.

The malicious contract’s fallback executes and re-calls the vulnerable function before the state is updated.

This loop drains the protocol’s funds.

Recommended Mitigation

Instead of pushing the amount back to the bidder , just create a mapping in which all the low bidders amount are mapped and bidders then can call a function and pull theior funds on their own , this protects the contract from reentracy attack .

or if giving back the low bidders their amount is important , then we can create a mapping to do this , using CAI (Check Affect Interact)
first updaing in the mapping that amount is trasnferred then doing external call and then if failed add that in witdraw function and re update the mapping that amount is not refunded .

instead of pusing the money to the previos biddder just add its details in the mapping , user and amount , so that user can call just withdraw function pull his own money

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

Lead Judging Commences

cryptoghost Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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