# Weak PRNG for security secrets

Check that keys, salts and tokens come from a CSPRNG, not time-seeded or math/rand sources

_Area: Web authentication and account takeover. Seen in 3 disclosed reports; latest 2026-08-07. Updated 2026-11-01._

## How it works
Security secrets are only as strong as the randomness behind them. When a key, salt, seed or token is drawn from a non-cryptographic PRNG (Math.random, Go math/rand) or seeded from a guessable value like the clock, the nominal bit count is a fiction. The real search space is the seed space, or whatever the PRNG can produce from it, and an attacker who can guess or recover the seed can regenerate the secret. A hash or KDF applied afterward cannot restore entropy that was never there [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-rg76-677x-56q9.md).

## Where it shows up
- Go code calling `math/rand` (especially `rand.Seed(time.Now().UnixNano())`) to build signing keys, salts or tokens [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md)
- JS libraries using `Math.random()` as the entropy source for `WordArray.random()` or similar helpers [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-rg76-677x-56q9.md)
- Secrets generated once at first startup and persisted, so a single weak draw protects everything forever [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md)
- A strong input seed passed through a shuffle or derivation step that collapses the output space [E3](https://bugbountylibrary.com/r/h1%3A3042475.md)
- Any public timestamp (install date, account creation) near the secret's generation time [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md)

## How to review
Trace every security-relevant secret to its actual entropy source. The invariant: the secret must be drawn from an OS CSPRNG (`crypto/rand`, `crypto.randomBytes`) with no time or `Math.random` seeding, and the effective output entropy must equal the nominal bit count. Count the real output space after any derivation or shuffle, not the input space [E3](https://bugbountylibrary.com/r/h1%3A3042475.md). For persisted secrets, ask whether the generation time is observable to an attacker [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md).

## Variants seen
- Library-level weak PRNG used as wallet entropy source, nominal 128/256 bits collapsing to ~2^39/2^47 [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-rg76-677x-56q9.md)
- Time-seeded `math/rand` generating JWT signing key and salt at startup [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md)
- Strong primary seed reduced to 1,024 values by a lossy shuffle step [E3](https://bugbountylibrary.com/r/h1%3A3042475.md)

## Impact and severity
Critical: forged admin JWTs and full account takeover [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md), brute-forced wallet seeds with ~$5M drained [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-rg76-677x-56q9.md), and anticheat bypass [E3](https://bugbountylibrary.com/r/h1%3A3042475.md). Severity rises when the weak secret is long-lived, globally trusted, or its generation time is publicly inferable.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-rg76-677x-56q9.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-f8xp-wvcx-p6f4.md
- E3: https://bugbountylibrary.com/r/h1%3A3042475.md
