clockworklabs / clockworklabs/SpacetimeDB

Clients can influence RNG output by calling reducers at specified times

Open
#3,358 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
25.2k
Forks
1.1k
Avg merge
2d 7h
Merged PRs (30d)
46

Description

Because ReducerContext.rng() is "seeded by the timestamp of the reducer call" clients can send the call at a specified time to influence the RNG output.

While we cannot hit a specified µs which would give us 100% control we can still hit bigger timing windows. They have a chance of being more "lucky" due to RNG output not being perfectly uniform over time. (as an example for coin toss it's perfectly reasonable to get a few heads in a row).

Here's an example table of attack window vs waiting time for a reducer rolling true with 10% probability:

#[spacetimedb::reducer]
pub fn rand(ctx: &ReducerContext) {
    let mut rng = ctx.rng();
    let result = rng.gen_ratio(1, 10);
    ctx.db.rng_results().insert(RngResult {
        id: 0,
        result,
    });
}
v Attack window - Waiting Time > 2 s 5 s 10 s 30 s 60 s
0.1 ms 26.00 % 27.00 % 27.00 % 27.00 % 27.00 %
0.5 ms 16.20 % 16.60 % 17.00 % 17.00 % 17.00 %
1.0 ms 14.60 % 14.60 % 14.70 % 14.70 % 14.70 %
5.0 ms 11.52 % 11.64 % 11.64 % 11.90 % 11.90 %
10.0 ms 11.07 % 11.18 % 11.18 % 11.29 % 11.29 %
50.0 ms 10.33 % 10.49 % 10.49 % 10.51 % 10.51 %
100.0 ms 10.21 % 10.25 % 10.28 % 10.30 % 10.37 %
500.0 ms 10.06 % 10.11 % 10.14 % 10.14 % 10.15 %
1000.0 ms 10.00 % 10.06 % 10.11 % 10.11 % 10.11 %

From my tests in real-world scenarios it's reasonable to hit a 500µs-2ms window.

Results for attacking a reducer rolling true 10% of the time hosted on Maincloud from a host in phoenixNAP Ashburn DC: ATTACK_RESULTS: 1379 / 10000 (10% -> 13.7900%)

Longer writeup: https://koz.omg.lol/2025/10/spacetimedb-rng-manipulation-attack

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the ReducerContext.rng() entry point and the reducer example in the issue, then reproduce the timing attack described in the writeup. Done means reducer callers can no longer improve RNG outcomes by choosing when to invoke the reducer, with coverage for the reported attack scenario.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.