Skip to content

VNX-339: Small Seed Space in Pseudo-Random Number Generator (PRNG)

Detects a PRNG seeded with a value narrowed to a small range (a modulus, a 16-bit mask or cast, a length or count, a small random range) when its output is security-relevant, and any narrowed seed on 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-339
Severity Medium
SARIF level warning
Kind sast
Languages Python, Java, Kotlin, Go, C, C++, PHP, Ruby, JavaScript / TypeScript
CWE CWE-339
CAPEC CAPEC-97
ATT&CK T1557
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-339
Source internal/sast/rules/vnx-339.rego

Overview

VNX-339 maps to CWE-339: Small Seed Space in PRNG. However strong the generator, a seed with a few thousand possible values gives a few thousand possible output sequences, and an attacker can try every one.

The rule reports a seed reduced with a modulus (x % 1000) or a mask of at most 16 bits (& 0xFFFF), cast to an 8- or 16-bit type ((short), (unsigned char), uint16_t, uint8(...)), taken from a length or count (key.length(), len(s), strlen(), .size()), or drawn from a small random range (randint(0, 999), nextInt(1000), Intn(256)), inline or through a variable assigned one of those within eight lines above, passed to the same seeding APIs as VNX-336.

A narrowed seed on a SecureRandom or ChaCha8 is always reported. A general-purpose PRNG is reported only when its output is security-relevant: 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 secret.

What Gets Flagged

// FLAGGED: the seed is the length of the key
public String createPasswordReset(String username, String key) {
    Random random = new Random();
    random.setSeed(key.length());
    return Integer.toHexString(random.nextInt());
}
// FLAGGED: a 16-bit seed for a SecureRandom
sr.setSeed(stamp & 0xFFFF);
/* FLAGGED: a thousand possible seeds */
srand(seed % 1000);
# FLAGGED: the seed comes from a 1000-value range
random.seed(random.randint(0, 999))

What Is Not Flagged

  • Full-width seeds, and narrowed seeds in files that produce no secret.
  • Test files, and calls in comments or string literals.

Constant seeds are VNX-336 and clock/PID seeds VNX-337; a seed that is both narrowed and clock-derived is reported by both.

Remediation

  1. Do not seed generators that produce secrets; use a CSPRNG that seeds itself from the operating system (secrets, SecureRandom, crypto/rand, random_bytes(), crypto.randomBytes()).
  2. For confirmed false positives, add a # vulnetix-ignore: VNX-339 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-339
// nosec vnx-339

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

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