Skip to content

Latest commit

 

History

History
83 lines (59 loc) · 2.97 KB

File metadata and controls

83 lines (59 loc) · 2.97 KB

S006 — Unsafe Pattern

  • Category: unsafe_patterns
  • Severity: Medium
  • Rule name: unsafe_pattern

What it detects

S006 is the catch-all for potentially unsafe language or runtime patterns that don't have a more specific code. The flagship case is timestamp-as-randomness: using env.ledger().timestamp() as entropy. The detector fires when env.ledger().timestamp() appears inside:

  • a function whose name contains rand, seed, pick, or winner, or
  • a variable binding whose name contains one of those tokens.

Other unsafe runtime patterns surface under the same category, each with a suggested safe alternative.

Why it matters

A block timestamp is not secret entropy. Validators can nudge env.ledger().timestamp() within a small window, so any "random" outcome derived from it — a lottery winner, a shuffled order, a seed — is predictable and manipulable. An attacker who can influence or predict the value can guarantee favorable outcomes and replay the exploit.

Vulnerable example

#![no_std]
use soroban_sdk::{contract, contractimpl, Env, Vec, Address};

#[contract]
pub struct Lottery;

#[contractimpl]
impl Lottery {
    pub fn pick_winner(env: Env, entrants: Vec<Address>) -> Address {
        // S006: timestamp used as the randomness source for the winner.
        let seed = env.ledger().timestamp();
        let index = (seed % entrants.len() as u64) as u32;
        entrants.get(index).unwrap()
    }
}

Safe example

#![no_std]
use soroban_sdk::{contract, contractimpl, Env, Vec, Address};

#[contract]
pub struct Lottery;

#[contractimpl]
impl Lottery {
    pub fn pick_winner(env: Env, entrants: Vec<Address>) -> Address {
        // Use the host PRNG, which is seeded from unpredictable entropy.
        let len = entrants.len();
        let index = env.prng().gen_range(0..len as u64) as u32;
        entrants.get(index).unwrap()
    }
}

CVSS-style risk rating

  • Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
  • Base score: 7.5
  • Rating: High

When the pattern is exploitable randomness, a low-complexity attacker can bias outcomes (high integrity impact), so the realized risk is high even though the catalog severity for the broad category is Medium.

How to fix

  1. Never use env.ledger().timestamp() (or sequence number) as a sole source of randomness.
  2. Use the Soroban host PRNG (env.prng()), seeded from a fresh entropy source.
  3. For high-value randomness, use a VRF oracle or commit-reveal scheme combining multiple unpredictable inputs.
  4. For other flagged patterns, apply the suggested safe alternative or add an explicit safety check.

Related rules

Related rules: S003, S002

References