September 12th, 2022
Timestamp dependence vulnerability is when a smart contract utilizes the block.timestamp function when performing critical logic in a smart contract. This includes actions such as sending ETH, or using the function as the source of entropy in order to generate necessary random numbers.
This function is easily manipulated since the value of the actual timestamp is generated by the node that creates a block containing a transaction that executes the smart contract code.
Block timestamps are flexible, and nodes will accept any timestamp within a certain window. This means that when a smart contract transfers ETH using block.timestamp, bad actors (miners) can exploit the vulnerability by manipulating the block timestamps themselves – setting up the conditions for their own success.
Take this contract for example, which contains timestamp dependence vulnerability:
A smart contract code sample that illustrates how timestamp dependence vulnerability works.
Since this smart contract seeds a random number using the block.timestamp function, it enables the miner to precompute a more favorable number for the lottery, posting an alternate timestamp within block validation time limit.
In the original whitepaper, Ethereum constrained timestamps to 15 minutes, but the more recent Ethereum ‘Yellow Paper’ has dropped the 15 minute limit, requiring only that the timestamp of a block be greater than the referenced previous block’s timestamp.
Popular Ethereum protocol implementations Geth and Parity, however, both reject blocks with timestamps more than 15 seconds in future (with average block times landing between 12-14 seconds). This means that if the scale of the time-dependent event can vary by 15 seconds and maintain integrity, it may be safe to use a block.timestamp for that function.
Similar to the timestamp dependence is block number dependency vulnerability. This happens when instead of using block.time, programmers estimate a time delta using block.number and average block time.
While it may seem more fool-proof than block.timestamp (since blocks advance one by one), alas, it too has vulnerabilities. Block times are subject to change due to fork reorganizations and other factors.
Preventing the timestamp dependence vulnerability is fairly simple. For random number generation, use a robust algorithm. For functions requiring time-triggered data, assess whether or not the scale of the time-dependent event can vary by 15 seconds and maintain integrity. If so, it may be safe to use a block.timestamp for that function.
Interested in learning about potential cybersecurity vulnerabilities and how to stop them before they occur? Connect with Halborn’s security experts at firstname.lastname@example.org.