Use crypto/rand for session tokens, reset codes, API keys and nonces. The math/rand package documentation says it should not be used for security sensitive work and points to crypto/rand instead. Better seeding in newer Go versions does not change that.
What the docs say
The overview of math/rand says the package is for tasks like simulation and "should not be used for security-sensitive work." It then points to crypto/rand for random numbers suitable for security sensitive work. The same warning appears on math/rand/v2.
The reason is the purpose of the generator. A general purpose generator is built for speed and statistical spread, not for an attacker who sees outputs and tries to predict what comes next.
Seeding changes that confuse people
Many old posts say that Go's math/rand is predictable because it is seeded the same way every run. That was true in the past:
- Before Go 1.20, the generator was seeded at startup as if by
Seed(1), so each run produced the same sequence. - Since Go 1.20, it is seeded randomly at startup if you do not call
Seed. The docs say there is no reason to callSeedwith a random value. - As of Go 1.24,
Seedis a no-op. You can restore the older behavior withGODEBUG=randseednop=0.
So modern math/rand does not repeat the same sequence on every start. That is a fix for a different problem. It still is not designed to resist prediction, and the docs still say not to use it for security.
A token with crypto/rand
package main
import (
"crypto/rand"
"encoding/base64"
)
func newToken() (string, error) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(b), nil
}
Check the error from rand.Read. Do not fall back to math/rand if it fails. Fail the request instead.
Where math/rand is fine
- Shuffling test data.
- Jitter for retry backoff.
- Picking a sample for logging.
- Games and simulations where predictability is not a harm.
Where it is not
- Session identifiers and CSRF tokens.
- Password reset and email verification codes.
- Encryption keys, nonces and salts.
- Anything that grants access to a resource if guessed.
A review shortcut: search for math/rand imports and look at the filename. Files in auth, session, token or billing packages deserve a second look.
Safeguard's SBOM and dependency scanning helps you track the libraries your Go services pull in, including those that generate tokens. Run a free scan at gold.safeguard.sh/scan. For the same question in Python, see secrets vs random.
Quick check
Does random seeding in Go 1.20 make math/rand safe for tokens?
No. It stops identical sequences on each start, but the docs still say not to use math/rand for security sensitive work.
What is the simplest safe replacement?
Read bytes with crypto/rand.Read and encode them, as in the example above.
Sources
Last reviewed: 19 October 2026.