crowdsecurity/crowdsec · error

CS_LAPI_SECRET not strong enough

Error message

CS_LAPI_SECRET not strong enough

What it means

NewJWT validates CS_LAPI_SECRET, the HMAC secret used to sign LAPI JWTs. If the variable is set but shorter than 64 characters it returns "CS_LAPI_SECRET not strong enough" and the API server fails to start. The length floor prevents trivially brute-forceable token-signing keys.

Source

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

	// 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
	secretString := os.Getenv("CS_LAPI_SECRET")
	secret = []byte(secretString)

	switch l := len(secret); {
	case l == 0:
		secret, err = randomSecret()
		if err != nil {
			return &JWT{}, err
		}
	case l < 64:
		return &JWT{}, errors.New("CS_LAPI_SECRET not strong enough")
	}

	jwtMiddleware := &JWT{
		DbClient: dbClient,
		TlsAuth:  &TLSAuth{},
	}

	ret, err := jwt.New(&jwt.GinJWTMiddleware{
		Realm:           "Crowdsec API local",
		Key:             secret,
		Timeout:         time.Hour,
		MaxRefresh:      time.Hour,
		IdentityKey:     MachineIDKey,
		PayloadFunc:     PayloadFunc,
		IdentityHandler: IdentityHandler,
		Authenticator:   jwtMiddleware.Authenticator,
		Authorizator:    Authorizator,
		Unauthorized:    Unauthorized,

View on GitHub (pinned to 909b515798)

Solutions

  1. Generate a ≥64-character secret, e.g. `export CS_LAPI_SECRET=$(head -c 48 /dev/urandom | base64)`
  2. Ensure all LAPI clients (agents, bouncers' registration flows) get the same secret when you change it
  3. Fix the deployment template/script that produces the short value
  4. Alternatively unset CS_LAPI_SECRET (length 0) to let crowdsec generate a random secret itself

Example fix

// before
CS_LAPI_SECRET=secret123
// after
export CS_LAPI_SECRET=$(head -c 48 /dev/urandom | base64 | tr -d '\n')
Defensive patterns

Strategy: validation

Validate before calling

if v := os.Getenv("CS_LAPI_SECRET"); v != "" && len(v) < 64 {
    return errors.New("CS_LAPI_SECRET must be at least 64 characters")
}

Try / catch

jwt, err := NewJWT(dbClient)
if err != nil {
    if strings.Contains(err.Error(), "not strong enough") {
        log.Fatal("regenerate CS_LAPI_SECRET with: head -c 48 /dev/urandom | base64")
    }
    return err
}

Prevention

When it happens

Trigger: CS_LAPI_SECRET exported with a short value (0 < len < 64) before starting crowdsec/LAPI — e.g. a placeholder like "changeme", a truncated paste, or a deployment script writing a short default.

Common situations: Kubernetes/docker deployments templating the secret with a short default; ansible scripts generating too-short passwords; users following outdated docs that suggested short secrets.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


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