Platform: Code4rena
Start Date: 31/01/2023
Pot Size: $36,500 CANTO
Total HM: 5
Participants: 38
Period: 3 days
Judge: berndartmueller
Total Solo HM: 2
Id: 212
League: ETH
Rank: 1/38
Findings: 2
Award: $6,680.61
🌟 Selected for report: 0
🚀 Solo Findings: 0
17055.7352 CANTO - $5,138.93
CidNFT.mint(bytes[]) allow user to mint and add subprotocol NFTs directly after minting. The _addList
args to the add call include the _cidNFTID
param, which can change if there are other mint before the user's transaction. Additionally, CidNFT.add only check if the cid nft is owned by msg.sender, OR if the msg.sender is approved to to cidnft; Thus, an attacker can front run the mint and add call, approve the victim to his newly mint cid nft, let the victim tx to be executed and therefore assigning his subprotocol nft to the attacker's cid nft, and revoke the approval.
Unlike the DOS attack, this is high risk because asset can be stolen.
CidNFT.mint(bytes[])
function mint(bytes[] calldata _addList) external { _mint(msg.sender, ++numMinted); // We do not use _safeMint here on purpose. If a contract calls this method, he expects to get an NFT back bytes4 addSelector = this.add.selector; for (uint256 i = 0; i < _addList.length; ++i) { ( bool success, /*bytes memory result*/ ) = address(this).delegatecall(abi.encodePacked(addSelector, _addList[i])); if (!success) revert AddCallAfterMintingFailed(i); } }
if ( cidNFTOwner != msg.sender && getApproved[_cidNFTID] != msg.sender && !isApprovedForAll[cidNFTOwner][msg.sender] ) revert NotAuthorizedForCIDNFT(msg.sender, _cidNFTID, cidNFTOwner);
Instead of a self delegate call, use a switch statement with abi.decode to support different type of entry, and call the internal function according with the newly generated cid nft id.
#0 - c4-judge
2023-02-09T11:54:15Z
berndartmueller marked the issue as duplicate of #67
#1 - c4-judge
2023-02-17T21:03:36Z
berndartmueller marked the issue as satisfactory
5116.7206 CANTO - $1,541.68
CidNFT.mint(bytes[]) allow user to mint and add subprotocol NFTs directly after minting. The _addList
args to the add call include the _cidNFTID
param, which can change if there are other mint before the user's transaction.
An attacker can DOS a user's mint and add by front-running their mint by another mint, bumping the cid nft id.
/// @notice Mint a new CID NFT /// @dev An address can mint multiple CID NFTs, but it can only set one as associated with it in the AddressRegistry /// @param _addList An optional list of encoded parameters for add to add subprotocol NFTs directly after minting. /// The parameters should not include the function selector itself, the function select for add is always prepended. function mint(bytes[] calldata _addList) external { _mint(msg.sender, ++numMinted); // We do not use _safeMint here on purpose. If a contract calls this method, he expects to get an NFT back bytes4 addSelector = this.add.selector; for (uint256 i = 0; i < _addList.length; ++i) { ( bool success, /*bytes memory result*/ ) = address(this).delegatecall(abi.encodePacked(addSelector, _addList[i])); if (!success) revert AddCallAfterMintingFailed(i); } }
Instead of a self delegate call, use a switch statement with abi.decode to support different type of entry, and call the internal function according with the newly generated cid nft id.
#0 - c4-judge
2023-02-09T12:05:38Z
berndartmueller marked the issue as duplicate of #67
#1 - c4-judge
2023-02-17T21:16:18Z
berndartmueller marked the issue as not a duplicate
#2 - c4-judge
2023-02-17T21:17:11Z
berndartmueller marked the issue as duplicate of #115
#3 - c4-judge
2023-02-17T21:17:22Z
berndartmueller marked the issue as satisfactory