One Shot: Reloaded

First Flight #47
Beginner FriendlyNFT
100 EXP
Submission Details
Impact: high
Likelihood: high

Insecure randomness source for battle outcomes.

Author Revealed upon completion

Root + Impact

Description

  • The normal behavior of the rap_battle module is to compute a winner based on the challenger and defender's skills. The specific issue is that the randomness used to determine the winner is derived from. timestanp:: now_seconds() This function returns a value that can be influenced or predicted by validators, making the outcome of the battle vulnerable to manipulation.Describe the normal behavior in one or more sentences

// Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:

  • A validator can include or delay transactions to influence the timestamp of the next block.

  • The rnd variable is a simple modulo of the timestamp, making its value predictable given the total skill.

Impact:

  • A malicious validator or user could guarantee victory, unfairly winning the entire prize pool.

  • This undermines the integrity and trust of the game, as battle outcomes are not truly random.

Proof of Concept

let defender_skill = one_shot::skill_of(arena.defender_token_id);
let challenger_skill = one_shot::skill_of(chall_token_id);
let total_skill = defender_skill + challenger_skill;
let rnd = timestamp::now_seconds() % (if (total_skill == 0) { 1 } else { total_skill }); @>
let winner = if (rnd < defender_skill) { defender_addr } else { chall_addr };

Recommended Mitigation

- let rnd = timestamp::now_seconds() % (if (total_skill == 0) { 1 } else { total_skill });
+ let rnd = get_secure_randomness() % (if (total_skill == 0) { 1 } else { total_skill });

Support

FAQs

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