How On-Chain Randomness Actually Gets Broken
Why block.timestamp and blockhash are not random, how the revert-on-loss attack defeats good entropy, and where the bugs hide in a Chainlink VRF integration.
By Alex Cipher
A blockchain is a deterministic replicated state machine. Every node must reach the same result from the same inputs, which means there is no genuine source of randomness inside the EVM — only values that are hard for some participants to predict. Every on-chain randomness bug is a variation on forgetting that.
Why block variables fail
The pattern below, or something close to it, still appears in production code:
uint256 result = uint256(
keccak256(abi.encodePacked(block.timestamp, msg.sender))
) % 100;Both inputs are fully known to the caller at the moment they build the transaction. An attacker does not need to break keccak256 — they compute the result themselves first and only send the transaction when the answer suits them. A contract calling this from inside the same block gets the same value.
Taking each source in turn:
block.timestamp— set by the block producer, who has room to adjust it. If the payout exceeds the value of the block, adjusting it is rational.block.number— entirely predictable. Not entropy in any sense.blockhash(block.number - 1)— known before your transaction executes, so anyone can compute the outcome and decide whether to proceed.block.prevrandao— better, but a proposer can choose to skip a slot to influence it, and it is known to the proposer in advance. Fine for low-stakes tie-breaking, unsuitable for anything worth attacking.msg.sender, nonces, balances — attacker-controlled. Contracts can be deployed until an address produces the desired result.
The attack that catches most teams
Here is the subtle part. Suppose you use a source the caller genuinely cannot predict. You may still be exploitable, because the attacker does not need to know the outcome in advance — they only need to reject outcomes they dislike.
If a contract can call your game and revert the whole transaction when the result is a loss, the attacker plays for free until they win. Gas is the only cost, and it is trivial against a meaningful jackpot.
Any design where the bet is placed and the outcome resolved in a single transaction is vulnerable to this, no matter how good the entropy is. Resolution must happen in a later transaction than the commitment.
Commit-reveal, and how it breaks
Commit-reveal separates the two steps: the player submits a hash of a secret, and reveals the secret later, after their commitment is locked in. The outcome combines the revealed secret with a value that was not known at commit time.
The failure modes are well known and still shipped regularly:
- Selective non-reveal. If a player can decline to reveal, they abort every losing round. Reveals must be economically forced — a stake that is slashed on non-reveal, with a default resolution.
- Reveal-window manipulation. If the window is too short a player can be censored out of it; too long and the reveal transaction can be sniped based on mempool contents.
- Weak secrets. If the committed value has a small search space, the hash can be brute-forced before reveal.
- Single-party entropy. If only the house contributes the second value, the house can cheat. If only the player does, the player can.
VRF, and where its bugs live
A verifiable random function — Chainlink VRF being the common choice — produces a value with a cryptographic proof that it was generated correctly and could not have been tampered with. This is the right default for anything where the outcome carries real value.
It moves the problem rather than eliminating it. In review, VRF bugs cluster in the integration:
- Unprotected callback. The fulfilment function must only be callable by the VRF coordinator. If anyone can call it, the randomness is whatever they pass in.
- Request-to-context mapping. Fulfilment is asynchronous. If request IDs are not mapped correctly to the game round and player, outcomes can be crossed or replayed.
- State mutable between request and fulfilment. If a player can raise their bet, or the house can change the payout table, after the request but before fulfilment, the pending outcome becomes exploitable. Lock all relevant state at request time.
- Unhandled fulfilment failure. If the callback runs out of gas or reverts, funds must not be stuck. There needs to be a timeout and refund path.
- Underfunded subscription. If the subscription runs dry, requests silently stop being fulfilled. Monitor it.
- Modulo bias. Mapping a uint256 onto a small range with
%skews the distribution. Usually negligible, but if your edge is thin, do it properly.
What I check during a review
- Trace the entropy to its origin, and identify every party who knows or influences it, and when.
- Confirm commitment and resolution are in different transactions.
- Check whether a contract caller can revert on an unfavourable outcome.
- Check whether any participant can decline to act and thereby avoid a loss.
- Verify the callback's access control and its request-to-round mapping.
- Confirm every state input to the outcome is frozen at request time.
- Check the failure path: timeout, refund, no stuck funds.
The rule of thumb
Assume every value your contract can read is known to the person calling it, and assume they will only send the transaction when it pays. If your design survives both assumptions, the randomness is probably sound. If it depends on the player not looking, it is already broken — the only open question is when someone checks.
This is one section of a broader piece on gambling dApp security. If you are shipping a game with real value on the line, I review this category specifically — GameFi and gambling dApp audits.
Keep reading
How Much Does a Smart Contract Audit Cost?
Real market rates for independent auditors, boutique firms, and top-tier firms — and the variables that actually move the number.
Best PracticesThe Pre-Launch Smart Contract Security Checklist
The checklist I run against a codebase before an audit begins — access control, accounting, oracles, upgrades, and the questions to answer before you hand anything over.