Bid Beasts

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

Centralization Risk

Description

  • Decentralized systems should minimize single points of control to reduce trust requirements and potential abuse.

  • Both contracts have privileged owner roles that can mint unlimited NFTs and withdraw all platform fees, creating centralization risks and potential for abuse.

@> contract BidBeastsNFTMarketPlace is Ownable(msg.sender) {
@> function withdrawFee() external onlyOwner {

Risk

Likelihood:

  • Owner privileges exist permanently unless explicitly renounced

  • Single entity controls critical contract functions

Impact:

  • Single point of failure for contract operations

  • Potential for owner to abuse privileges or act maliciously

Proof of Concept

function test_LOW_L1_CentralizationRisk() public {
// NFT contract owner can mint unlimited tokens
vm.startPrank(OWNER);
// Owner can mint as many NFTs as desired
uint256 tokenId1 = nft.mint(OWNER);
uint256 tokenId2 = nft.mint(OWNER);
uint256 tokenId3 = nft.mint(OWNER);
vm.stopPrank();
// Verify owner minted multiple tokens
assertEq(nft.ownerOf(tokenId1), OWNER);
assertEq(nft.ownerOf(tokenId2), OWNER);
assertEq(nft.ownerOf(tokenId3), OWNER);
// Marketplace owner can withdraw all accumulated fees
uint256 tokenId = _mintAndListNFT(ALICE, MIN_PRICE, 0);
vm.prank(BOB);
market.placeBid{value: MIN_PRICE + 0.1 ether}(tokenId);
vm.warp(block.timestamp + 16 minutes);
vm.prank(CHARLIE);
market.settleAuction(tokenId);
// Owner can withdraw all fees
uint256 totalFees = market.s_totalFee();
assertGt(totalFees, 0, "Should have accumulated fees");
vm.prank(OWNER);
market.withdrawFee();
assertEq(market.s_totalFee(), 0, "Fees should be withdrawn");
}

Recommended Mitigation

+ import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
- contract BidBeastsNFTMarket is Ownable(msg.sender) {
+ contract BidBeastsNFTMarket is AccessControl {
+ bytes32 public constant FEE_MANAGER_ROLE = keccak256("FEE_MANAGER_ROLE");
+
+ constructor(address _BidBeastsNFT) {
+ _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
+ _grantRole(FEE_MANAGER_ROLE, msg.sender);
+ BBERC721 = BidBeasts(_BidBeastsNFT);
+ }
- function withdrawFee() external onlyOwner {
+ function withdrawFee() external onlyRole(FEE_MANAGER_ROLE) {
// ... rest of function
}
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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