Company Simulator

First Flight #51
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

[L-03] - Predictable randomness in `trigger_demand()` allows front-running

Root + Impact

Description

The trigger_demand() function in CustomerEngine.vy simulates customer demand, which includes a random chance of success based on the company's reputation.

The "randomness" is generated using block.timestamp and block.number.

# Root cause in the codebase (Cyfrin_Hub.vy)
@internal
def sell_to_customer(requested: uint256, customer: address, amount_paid: uint256):
# ...
# Determine success probability based on reputation
success_probability: uint256 = (self.reputation * 100) / 100 # Simplified for clarity
# Generate "random" number
random_seed: uint256 = block.timestamp + block.number # @> Uses predictable block variables
random_number: uint256 = (random_seed % 100) + 1
# Check if sale is successful
if random_number <= success_probability:
# ...

Since both block.timestamp and block.number are public blockchain variables, they can be predicted and manipulated by miners or sophisticated attackers.

Risk

Likelihood: Low
The attack requires a miner or a sophisticated attacker to front-run the transaction and calculate the exact outcome of the sale before it is executed. While possible, the economic incentive for this specific attack is low.

Impact: Low
The impact is limited to the outcome of a single sale, allowing an attacker to guarantee a successful sale when the reputation is low, or avoid a transaction that would fail. No funds are directly at risk.

Proof of Concept

A miner can calculate the exact random_number before including the transaction in a block.

# Attacker's calculation (identical to contract's)
attacker_seed: uint256 = block.timestamp + block.number
attacker_random: uint256 = (attacker_seed % 100) + 1

If the attacker_random is greater than the success_probability, the attacker can choose not to submit the transaction, saving gas.

Recommended Mitigation

For on-chain randomness, it is recommended to use a more secure solution like Chainlink VRF or a commit-reveal scheme.

# Mitigation: Use a secure, off-chain randomness source (e.g., Chainlink VRF)
# or a commit-reveal scheme.
@internal
def sell_to_customer(requested: uint256, customer: address, amount_paid: uint256):
# ...
- random_seed: uint256 = block.timestamp + block.number
- random_number: uint256 = (random_seed % 100) + 1
+ # Replace with secure randomness source
+ random_number: uint256 = get_secure_random_number() # Placeholder for VRF call
# Check if sale is successful
if random_number <= success_probability:
# ...
Updates

Lead Judging Commences

0xshaedyw Lead Judge
9 days ago
0xshaedyw Lead Judge 7 days ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.