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

[L-1] Random APT amount for the slice can be predicted based on the time of the registration

Root + Impact

Description

  • The function to get the random amount of APT for the slide is based on time mod on 401, that can easily guessed by an attacker

  • When knowing which occurrences on time gives the maximum

#[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:

  • If the attacker knows when in time the owner will register the users, can manipulate the request to maximize the chances to get the highest reward

  • If the owner is aware and wants to rig the system

Impact:

  • It defies the main purpose of randomnes by giving the exact amount on rewards the user will get based on the time of registration

Proof of Concept

A quick query with AI will list all the iterations of the epoch in milliseconds of the day where you can get the 500 APT

The first 4 ocurrencies for 29 of August that will get the 400

  1. Timestamp: 1756425600000110

    • Time (UTC): 2025-08-29 00:00:00.000110

  2. Timestamp: 1756425600000511

    • Time (UTC): 2025-08-29 00:00:00.000511

  3. Timestamp: 1756425600000912

    • Time (UTC): 2025-08-29 00:00:00.000912

  4. Timestamp: 1756425600001313

    • Time (UTC): 2025-08-29 00:00:00.001313

Recommended Mitigation

Use the random generator from aptos framework for randomize the number between 0 and 400

use aptos_framework::randomness::{u64_range};
#[randomness]
entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
// Securely generate a random value in the desired range (0 to 400)
let random_val = u64_range(0, 400);
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 9 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.

emerjux Submitter
8 days ago
bube Lead Judge
8 days ago
bube Lead Judge 6 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.