crowdsecurity/crowdsec · error

master secret is %d bytes; minimum is %d

Error message

master secret is %d bytes; minimum is %d

What it means

NewChallengeRuntime validates the configured master_secret length and rejects anything shorter than minSecretBytes. The challenge cookie keyring derives keys from this secret, so a too-short secret is insecure and startup is aborted. Note: an empty/absent secret is auto-generated with a warning, but a present-but-short secret is a hard error.

Source

Thrown at pkg/appsec/challenge/challenge.go:410

	}

	logger := resolvedOpts.logger
	if logger == nil {
		logger = logging.SubLogger(log.StandardLogger(), "challenge", 0)
	}

	secret := resolvedOpts.masterSecret
	if secret == nil {
		var err error
		secret, err = generateRandomSecret()
		if err != nil {
			return nil, err
		}
		logger.Warn("no master secret configured for the WAF challenge runtime; generated an ephemeral random secret. " +
			"Distributed (multi-WAF) deployments MUST configure a shared master_secret in the appsec config; " +
			"single-instance deployments will see outstanding challenge cookies invalidated on restart.")
	} else if len(secret) < minSecretBytes {
		return nil, fmt.Errorf("master secret is %d bytes; minimum is %d", len(secret), minSecretBytes)
	}

	rotationInterval := resolvedOpts.rotationInterval
	if rotationInterval == 0 {
		rotationInterval = keyringDefaultRotation
	}

	keys, err := NewKeyRing(secret, rotationInterval, resolvedOpts.maxLiveEpochs)
	if err != nil {
		return nil, fmt.Errorf("build challenge keyring: %w", err)
	}
	keys.logger = logger

	cookieTTL := resolvedOpts.cookieTTL
	if cookieTTL <= 0 {
		cookieTTL = defaultCookieTTL
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Set a master_secret of at least minSecretBytes bytes (32+ bytes recommended): openssl rand -base64 32.
  2. In multi-WAF deployments, share the same sufficient-length secret across all AppSec instances.
  3. Remove the master_secret field entirely to let the runtime generate an ephemeral one (single-instance only).
  4. Store the secret via your config management/secrets manager rather than typing a short one manually.

Example fix

// before (appsec config)
master_secret: changeme
// after
generate with: openssl rand -base64 32
master_secret: kJ8fQ2xN7vR4tYw9zLm3Bc6aHd1pSg5XeU0iFo8kZrTn=
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate secret length before writing config
const minSecretBytes = 32
secret, _ := base64.StdEncoding.DecodeString(cfg.MasterSecret)
if len(secret) < minSecretBytes {
    return fmt.Errorf("master_secret too short: %d bytes, need >= %d", len(secret), minSecretBytes)
}

Try / catch

cr, err := NewChallengeRuntime(...)
if err != nil {
    if strings.Contains(err.Error(), "master secret is") {
        return fmt.Errorf("appsec config: %w (generate with `openssl rand -base64 32`)", err)
    }
    return err
}

Prevention

When it happens

Trigger: Configuring the AppSec challenge runtime with a master_secret whose length is below minSecretBytes (e.g. 'secret', 'abc123').

Common situations: Hand-written appsec config with a short placeholder secret; operators shortening a secret to fit some other system; copy-pasted example config values.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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