crowdsecurity/crowdsec · critical

unable to generate a new random seed for JWT generation

Error message

unable to generate a new random seed for JWT generation

What it means

randomSecret generates the 64-byte HMAC seed used to sign LAPI JWTs via crypto/rand.Read. It returns "unable to generate a new random seed for JWT generation" when rand.Read returns an error, meaning the OS random source could not be read. Without this seed the API server cannot issue tokens, so NewJWT fails and startup aborts.

Source

Thrown at pkg/apiserver/middlewares/v1/jwt.go:257

func Authorizator(data any, c *gin.Context) bool {
	return true
}

func Unauthorized(c *gin.Context, code int, message string) {
	c.JSON(code, gin.H{
		"code":    code,
		"message": message,
	})
}

func randomSecret() ([]byte, error) {
	size := 64
	secret := make([]byte, size)

	n, err := rand.Read(secret)
	if err != nil {
		return nil, errors.New("unable to generate a new random seed for JWT generation")
	}

	if n != size {
		return nil, errors.New("not enough entropy at random seed generation for JWT generation")
	}

	return secret, nil
}

func NewJWT(dbClient *database.Client) (*JWT, error) {
	// Get secret from environment variable "SECRET"
	var (
		secret []byte
		err    error
	)

	// Please be aware that brute force HS256 is possible.
	// PLEASE choose a STRONG secret

View on GitHub (pinned to 909b515798)

Solutions

  1. Set a strong CS_LAPI_SECRET (>=64 chars) so the random-seed path is never taken
  2. Verify getrandom(2)//dev/urandom is permitted for the crowdsec process (seccomp, apparmor, selinux)
  3. Test entropy availability: `head -c 64 /dev/urandom | xxd` on the host
  4. Restart the service after fixing the environment

Example fix

// docker-compose: unblock getrandom
security_opt:
  - seccomp:default.json  # or remove a custom profile blocking getrandom
// or pre-set the secret
environment:
  - CS_LAPI_SECRET=aVeryLongRandomStringOfAtLeast64Characters...
Defensive patterns

Strategy: fallback

Validate before calling

# ensure the secret env is set before launch so randomSecret is skipped:
test ${#CS_LAPI_SECRET} -ge 64 || echo "CS_LAPI_SECRET short or unset; will need OS entropy"

Try / catch

jwt, err := NewJWT(dbClient)
if err != nil {
    log.Fatalf("cannot start LAPI auth: %v", err) // fail fast with a clear message
}

Prevention

When it happens

Trigger: crowdsec starts with an empty/zero-length CS_LAPI_SECRET so it falls into the randomSecret branch, and crypto/rand.Read errors — e.g. getrandom(2) blocked by seccomp, or a broken entropy setup on the host.

Common situations: Highly restricted containers/jails blocking getrandom; corrupted or misconfigured minimal systems; embedded platforms with an unusable random device.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/f7e9d614338d2b1f. Report an issue: GitHub.