The RandomizerNXT.calculateTokenHash function is used to calculate the random hash and returns it to the gencore contract. The random hash is calculated as shown below:
Here the randoms.randomNumber() and randoms.randomWord()) (here randoms is an instance of the XRandoms contract) functions are called to obtain the respective randomness to the calculation of the random hash.
The XRandoms.randomNumber function and XRandoms.randomWord function uses the following computations to calculate the randomNum respectively, as shown below:
But the issue is that the solidity documentation says block.number and block.timestamp should not be relied upon for randomness as shown below:
Do not rely on block.timestamp or blockhash as a source of randomness, unless you know what you are doing.
Further block.prevrandao is also manipulatable since the randomness from the past is known and predictable, as explained in the following article:
https://soliditydeveloper.com/prevrandao
As a result the random hash value calculated in the RandomizerNXT.calculateTokenHash is not truly random since its randomness is predictable and can be manipulated by the validators. Hence the NextGenCore.tokenToHash value for a specific TokenId can be manipulated as a result. Since the tokenToHash[tokenId] is used in the NextGenCore.retrieveGenerativeScript function to create the Generative Script of a token and this generative script is used to calculate the tokenURI of a token when the onchainMetadata[tokenIdsToCollectionIds[tokenId]] == true, it can be concluded that the tokenURI of a ERC721 token is manipulatable when the RandomizerNXT is used as the randomizer contract of a specific collection (Since the returned random hash via the calculateTokenHash function is not truly random).
Hence it is recommended to only use the RandomizerRNG and RandomizerVRF contracts for the random hash generation during the ERC721 token miniting process.
Or else recommended to pick a future prevrandao value when using the block.prevrandao as explained in the https://soliditydeveloper.com/prevrandao article. This will ensure block.prevrandao can be used in a more secure way to generate the randomness.
Lines of code
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/RandomizerNXT.sol#L55-L59 https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/XRandoms.sol#L36 https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/XRandoms.sol#L41
Vulnerability details
Impact
The
RandomizerNXT.calculateTokenHash
function is used to calculate the random hash and returns it to thegencore
contract. Therandom hash
is calculated as shown below:Here the
randoms.randomNumber()
andrandoms.randomWord())
(here randoms is an instance of the XRandoms contract) functions are called to obtain the respective randomness to the calculation of the random hash.The
XRandoms.randomNumber
function andXRandoms.randomWord
function uses the following computations to calculate therandomNum
respectively, as shown below:But the issue is that the solidity documentation says
block.number
andblock.timestamp
should not be relied upon forrandomness
as shown below:Further
block.prevrandao
is also manipulatable since therandomness from the past is known and predictable
, as explained in the following article: https://soliditydeveloper.com/prevrandaoAs a result the
random hash
value calculated in theRandomizerNXT.calculateTokenHash
is not truly random since its randomness is predictable and can be manipulated by the validators. Hence theNextGenCore.tokenToHash
value for a specificTokenId
can be manipulated as a result. Since thetokenToHash[tokenId]
is used in theNextGenCore.retrieveGenerativeScript
function to create theGenerative Script
of a token and this generative script is used to calculate thetokenURI
of a token when theonchainMetadata[tokenIdsToCollectionIds[tokenId]] == true
, it can be concluded that thetokenURI
of a ERC721 token is manipulatable when theRandomizerNXT
is used as therandomizer
contract of a specific collection (Since the returned random hash via thecalculateTokenHash
function is not truly random).Proof of Concept
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/RandomizerNXT.sol#L55-L59
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/XRandoms.sol#L36
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/XRandoms.sol#L41
Tools Used
Manual Review and VSCode
Recommended Mitigation Steps
Hence it is recommended to only use the
RandomizerRNG
andRandomizerVRF
contracts for the random hash generation during the ERC721 token miniting process.Or else recommended to
pick a future prevrandao value
when using theblock.prevrandao
as explained in thehttps://soliditydeveloper.com/prevrandao
article. This will ensureblock.prevrandao
can be used in a more secure way to generate the randomness.Assessed type
Other