Safeguard
Security Guides•

Go math/rand vs crypto/rand: which is safe for tokens?

Use crypto/rand for tokens, keys and anything guessable in Go. What the math/rand docs say about security work and how seeding changed in Go 1.20 and 1.24.

Safeguard Security Team
3 min read

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 call Seed with a random value.
  • As of Go 1.24, Seed is a no-op. You can restore the older behavior with GODEBUG=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.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.