Hashmask Art Sale Bug Report
This bug was not exploited and no longer can be. No funds or Hashies are at risk, nor is the integrity of the Hashmask system compromised.
Executive Summary
- During late stages of the Hashmasks sale, samczsun reported a potential bug in our Masks.sol smart contract, specifically in the mintNFT function
- This bug was not exploited and no longer can be. No funds or Hashies are at risk, nor is the integrity of the Hashmask system compromised
- This exploit would have enabled an attacker to mint more than 16,384 Hashmasks
- This was a convoluted bug that escaped our rigorous testing and internal and external review
- We have awarded samczun $12,500 USDC for the bug disclosure
Some Technical Details
In the mintNFT function on Masks.sol contract, there is a method call to an internal function called _safeMint that then calls _checkOnERC721Received. If the sending address is a contract, this function further invokes IERC721Receiver-onERC721Received function on the sending address.
An exploit contract could implement logic to re-enter the mintNFT function in the onERC721Received function. This re-entrancy would still have to respect the conditional checks such as totalSupply or Ether value sent. However, it would allow the contract to mint more than 16,384 Hashmasks because once the re-entered execution completes, the loop containing _safeMint execution continues to be processed without a conditional check on totalSupply.
If timed perfectly correctly, the maximum number of extra masks mintable mathematically would have been 210 (20 + 19 + … 1). However, in practise, the maximum extra masks mintable would have been something around 60 due to the block gas limit. (Note: We haven’t simulated to verify this value of 60 and this is just a back of the envelope calculation with regard to the gas limit).
Our Internal Assessment
We classified the potential exploit to be a ‘Medium’ impact one considering a few factors. Firstly, it does not affect the NCT or NFT balances of existing holders, nor does it cause an interruption to the whole system’s functioning. It would have compromised the integrity of the intended maximum of 16,384 Hashmasks. It could also have prevented startingindexBlock from being set.
Given the chances of timing (even with a smart contract execution) and lack of strong economic incentives, we assessed the bug’s probability of being exploited to be very low. Nevertheless, we have discussed the plan in the case of an exploit.
The Plan in the Case of an Exploit
In the unlikely case the bug was exploited. For the extra minted Hashmasks, we planned to assign ‘Glitch masks’ to these invalids. They would have continued to be a part of the Hashmasks art history whilst not detracting from the value of other Hashmasks nor the system as a whole.
For the potential consequence of startingIndex, our mitigation plan was to deploy a separate contract as a store of the correct startingIndex. This startingIndex would be derived from the last transaction (what should have been) and this separate contract would have been considered the single source of truth for the startingIndex. It’s not the cleanest solution but still has solid provenance since anyone can verify if the derivation matches the last mint transaction from chain history.
We thank samczsun for his disclosure and integrity. Please direct any further questions about the bug to the #Support section of our Discord channel.
Disclaimer
The information contained on this website is not intended for individuals or entities who are ordinarily resident in the United States of America or Switzerland nor for residents of a geographic area that is subject to UN-, US-, EU- or Swiss sanctions or embargoes, including Afghanistan, Albania, Belarus, Bosnia & Herzegovina, Burundi, Central African Republic, Cote d’Ivoire, Cuba, Democratic Republic of the Congo, Ethiopia, Guinea, Guinea-Bissau, Iran, Iraq, Lebanon, Liberia, Libya, Myanmar (Burma), North Korea, Republic of Macedonia (FYROM), Serbia, Somalia, South Sudan, Sri Lanka, Sudan, Syria, Thailand, Trinidad & Tobago, Tunisia, Uganda, Ukraine, Venezuela, Yemen, and Zimbabwe. By entering or using the website, you accept you represent and warrant that you are not resident in those countries. The company reserves the right to restrict the sale of the NFT token in any jurisdiction or to any individuals or entities at its discretion.
The Company provides the website and its connected services “as is” and “as available,” without warranty of any kind. Without limiting this, we expressly disclaim all warranties, whether expressed, implied or statutory, regarding the website. Using applications on the blockchain is associated with a high degree of technological and/or other risks. Holders and/or purchaser of the NFT-Tokens and associated artwork are subject to the Terms and Conditions available on the website.
The NFT-Token are non-fungible tokens representing ownership of a digital artwork only. Accordingly, no information on this website (or any other documents mentioned therein) is or may be considered to be advice or an invitation to enter into an agreement for any investment purpose. Further, as NFT-Token represent artwork, nothing on this websites qualifies or is intended to be an offering of securities in any jurisdiction nor does it constitute an offer or an invitation to purchase shares, securities or other financial product.
Due to the artistic nature of the project, neither this document nor the NFT and the Token (which is provided for free at a set rate) have not been registered with or approved by any regulator in any jurisdiction. It remains in your responsibility to assure that the purchase of the NFT and Token (which is provided for free at a set rate), as well as the associated art is in compliance with laws and regulations in your jurisdiction.
We undertake no obligation to publicly update or revise any information or opinions published on the website. We reserve the right to amend the information at any time without prior notice.