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

Weak Randomness in get_random_slice

Root + Impact

Description

  • Describe the normal behavior in one or more sentences

    Answer: The contract intends to assign each user a random amount of APT between 100 and 500 (in Octas) upon registration. This should prevent users from predicting or influencing their assigned reward.

  • Explain the specific issue or problem in one or more sentences

    Answer: The contract uses the current timestamp (timestamp::now_microseconds()) modulo 401 to determine the random reward. Timestamps are public, predictable, and miner/validator-influenced, meaning the “randomness” is not actually secure. An attacker can time their transaction to get the maximum or minimum reward.

#[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
table::add(&mut state.users_claimed_amount, user_addr, random_amount);
}

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

    Answer: This will always occur when a user is registered since reward calculation relies solely on timestamp.

  • Reason 2

    Answer: Validators/miners can manipulate timestamps slightly, and users can spam transactions until they hit favorable values.

Impact:

  • Impact 1

    Answer: Attackers can consistently obtain maximum slices (close to 500 APT), draining the airdrop pool faster.

  • Impact 2

    Answer: Honest users receive smaller random values, creating an unfair distribution and potential contract bankruptcy.

Proof of Concept

Owner legitimately registers a user.

Attacker predicts the assigned pizza slice size since it’s derived from timestamp::now_microseconds() % 401. By creating many addresses and calling register_pizza_lover repeatedly until the modulus produces a high value, attacker ensures a maximum reward (500 APT).

#[test_only]
module pizza_drop::poc_exploit {
use pizza_drop::airdrop;
use aptos_framework::account;
use aptos_framework::timestamp;
use std::debug;
#[test(deployer = @pizza_drop, attacker = @0xBAD, framework = @0x1)]
fun test_predictable_randomness_exploit(
deployer: &signer,
attacker: &signer,
framework: &signer
) acquires airdrop::State, airdrop::ModuleData {
// Setup environment
timestamp::set_time_has_started_for_testing(framework);
account::create_account_for_test(@pizza_drop);
airdrop::init_module(deployer);
// Attacker spawns multiple accounts to brute-force high rewards
let mut i = 0;
while (i < 10) {
let new_addr = @0x100 + i;
account::create_account_for_test(new_addr);
// Register vulnerable function
airdrop::register_pizza_lover(deployer, new_addr);
// Check the amount
let amount = airdrop::get_claimed_amount(new_addr);
debug::print(&b"Attacker registered with reward: ");
debug::print(&amount);
// Jackpot case: 500 APT
if (amount == 500) {
debug::print(&b"💰 Attacker hit max reward!");
};
i = i + 1;
};
}
}

This test demonstrates how an attacker can game the random function by exploiting predictable timestamp-based randomness.

Recommended Mitigation

Use Aptos’ native randomness source instead of timestamp. The aptos_std::rand or #[randomness] API provides secure, verifiable randomness that cannot be manipulated by attackers.

- remove this code
- let time = timestamp::now_microseconds();
- let random_val = time % 401;
- let random_amount = 100 + random_val;
+ add this code
+ // Use on-chain secure randomness API
+ let rand_val = aptos_std::rand::u64_range(100, 501);
+ let random_amount = rand_val;
Updates

Appeal created

bube Lead Judge 12 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.