Beginner FriendlyGameFi
100 EXP
View results
Submission Details
Severity: medium
Valid

`timestamp::now_microseconds()` is predictable and manipulable by block producers

Root + Impact

Description

  • Normal behavior: During registration, the contract assigns the user a random slice size and stores it in users_claimed_amount. Later, the user claims exactly that assigned amount from the resource account balance.

  • Issue: get_random_slice derives randomness from timestamp::now_microseconds() and reduces it with % 401. Block producers can influence timestamps within consensus bounds, making outcomes predictable and biasable. The #[randomness] attribute is present but no aptos_framework::randomness API is used.

// sources/pizza_drop.move
#[randomness]
entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
@> let time = timestamp::now_microseconds();
let random_val = time % 401;
let random_amount = 100 + random_val; // 100-500 APT (in Octas: 10^8 smallest unit)
table::add(&mut state.users_claimed_amount, user_addr, random_amount);
}

Risk

Likelihood:

  • Validators routinely set/adjust block timestamps within allowed skew during registration transactions; the monotonic, low-entropy input produces predictable residues in % 401.

Impact:

  • Fairness is undermined: attackers bias for larger slices.

Recommended Mitigation

#[randomness]
entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
- let time = timestamp::now_microseconds();
- let random_val = time % 401;
+ let random_amount = randomness::u64_range(100, 501); // 100-500 inclusive
- let random_amount = 100 + random_val; // 100-500 APT (in Octas: 10^8 smallest unit)
table::add(&mut state.users_claimed_amount, user_addr, random_amount);
}
Updates

Appeal created

bube Lead Judge 11 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Predictable randomness

The `get_random_slice` function should only be called by the owner via the `register_pizza_lover` function. Also, the `owner` is trusted and will not choose a specific time for a new user to register. Therefore, I disagree with the claim of most reports in this group that an attacker can manipulate the random number of pizza slices. But I agree with the root cause of the reports in this group, that the random distribution is not completely random.

Support

FAQs

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