Skip to content

VNX-336: Same Seed in Pseudo-Random Number Generator (PRNG)

Detects a PRNG seeded with a constant (a literal, an ALL_CAPS constant or a variable assigned one) when its output is security-relevant, and any seeded SecureRandom or ChaCha8. Python, Java, Kotlin, Go, C, C++, PHP, Ruby and JavaScript.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-336
Severity Medium
SARIF level warning
Kind sast
Languages Python, Java, Kotlin, Go, C, C++, PHP, Ruby, JavaScript / TypeScript
CWE CWE-336
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags prng seed cwe-336
Source internal/sast/rules/vnx-336.rego

Overview

VNX-336 maps to CWE-336: Same Seed in Pseudo-Random Number Generator (PRNG). A generator seeded with a constant produces the same sequence on every run, so anyone who reads the code, or observes one run, knows every value it will produce.

The rule reports a constant seed (a number, a string or byte literal, an ALL_CAPS constant, or a variable assigned one of those within eight lines above) passed to random.seed()/random.Random(), new Random()/Random()/setSeed()/new SecureRandom(bytes), Go rand.Seed/NewSource/NewPCG/NewChaCha8, C/C++ srand/srandom/srand48/seed48 and the <random> engine constructors and .seed(), PHP mt_srand/srand and the Random\Engine constructors, Ruby srand/Random.new/Random.srand, and JavaScript seedrandom().

A seeded SecureRandom or ChaCha8 is always reported. A general-purpose PRNG is reported only when its output matters: the seed call sits in a function named for a secret, the generator is stored under a secret’s name, or the same file draws from a PRNG into a token, password, key, salt, nonce, OTP, CSRF or session value.

What Gets Flagged

# FLAGGED: fixed seeds, and the file draws a reset token from the generator
random.seed(1337)
rng = random.Random(42)

def make_reset_token():
    return "".join(random.choices(string.ascii_letters, k=32))
// FLAGGED: generator stored under a secret's name
private static final Random TOKEN_RNG = new Random(9001L);
// FLAGGED: a seeded SecureRandom is deterministic
sr.setSeed("acme-static-seed".getBytes(StandardCharsets.UTF_8));
// FLAGGED: ChaCha8 is fully determined by its seed
return rand.NewChaCha8([32]byte([]byte("0123456789abcdef0123456789abcdef")))

What Is Not Flagged

  • Reproducible seeds in simulations, data generators, games and benchmarks where nothing in the file is a secret. numpy and other library generators are not examined.
  • Unseeded or OS-seeded generators: random.seed(), new SecureRandom(), rand.New(rand.NewSource(time...)) (clock seeds are VNX-337).
  • Test files, and calls in comments or string literals.

Seeds narrowed to a small range are VNX-339.

Remediation

  1. Generate secrets with a CSPRNG that seeds itself from the operating system: secrets, SecureRandom (never seeded by hand), crypto/rand, random_bytes(), crypto.randomBytes(), SecureRandom.hex.
  2. Keep fixed seeds for reproducible simulations and tests only, in code that produces no secrets.
  3. For confirmed false positives, add a # vulnetix-ignore: VNX-336 comment on the line.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-336
// nosec vnx-336

Or record an ignore rule: vulnetix ignore add --rule vnx-336 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-336.rego, cli/internal/sast/docs/vnx-336.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.