{"record":{"id":"b43e6e92ba0f300e","repo":"crowdsecurity/crowdsec","slug":"build-challenge-keyring-w","errorCode":null,"errorMessage":"build challenge keyring: %w","messagePattern":"build challenge keyring: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/appsec/challenge/challenge.go","lineNumber":420,"sourceCode":"\t\tsecret, err = generateRandomSecret()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tlogger.Warn(\"no master secret configured for the WAF challenge runtime; generated an ephemeral random secret. \" +\n\t\t\t\"Distributed (multi-WAF) deployments MUST configure a shared master_secret in the appsec config; \" +\n\t\t\t\"single-instance deployments will see outstanding challenge cookies invalidated on restart.\")\n\t} else if len(secret) < minSecretBytes {\n\t\treturn nil, fmt.Errorf(\"master secret is %d bytes; minimum is %d\", len(secret), minSecretBytes)\n\t}\n\n\trotationInterval := resolvedOpts.rotationInterval\n\tif rotationInterval == 0 {\n\t\trotationInterval = keyringDefaultRotation\n\t}\n\n\tkeys, err := NewKeyRing(secret, rotationInterval, resolvedOpts.maxLiveEpochs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"build challenge keyring: %w\", err)\n\t}\n\tkeys.logger = logger\n\n\tcookieTTL := resolvedOpts.cookieTTL\n\tif cookieTTL <= 0 {\n\t\tcookieTTL = defaultCookieTTL\n\t}\n\n\tmaxCookieLen := resolvedOpts.maxCookieLen\n\tif maxCookieLen <= 0 {\n\t\tmaxCookieLen = MaxCookieLen\n\t}\n\n\tcryptoPoolSize := resolvedOpts.cryptoObfuscationPoolSize\n\tif cryptoPoolSize <= 0 {\n\t\tcryptoPoolSize = cryptoObfuscationPoolDefaultSize\n\t}\n","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/challenge.go#L402-L438","documentation":"NewChallengeRuntime wraps errors from NewKeyRing with 'build challenge keyring'. The keyring derives signing/encryption keys from the master secret for challenge cookie sealing with epoch rotation; failure means the keyring could not be initialized (typically an invalid secret or rotation/epoch parameters).","triggerScenarios":"NewChallengeRuntime -> NewKeyRing(secret, rotationInterval, maxLiveEpochs) returns an error — e.g. invalid key material or out-of-range rotation/maxLiveEpochs options.","commonSituations":"Misconfigured rotation_interval or max_live_epochs in the appsec challenge options; a secret that fails key derivation constraints despite passing length checks.","solutions":["Read the wrapped %w error for the exact NewKeyRing failure reason.","Check the challenge options: rotation_interval and max_live_epochs must be positive and sane; reset them to defaults if unsure.","Regenerate master_secret (openssl rand -base64 32) and retry.","Compare your config against the upstream default example for the appsec challenge runtime."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate options before construction\nif opts.RotationInterval != 0 && opts.RotationInterval <= 0 {\n    return errors.New(\"rotation_interval must be positive\")\n}\nif opts.MaxLiveEpochs < 0 {\n    return errors.New(\"max_live_epochs must be non-negative\")\n}","typeGuard":null,"tryCatchPattern":"keys, err := NewKeyRing(secret, rotationInterval, maxLiveEpochs)\nif err != nil { return nil, fmt.Errorf(\"build challenge keyring: %w\", err) } // inspect wrapped cause for which parameter failed","preventionTips":["Keep rotation_interval/max_live_epochs at defaults unless you have a reason","Unit-test NewKeyRing with your production config values","Log the wrapped error's cause, not just the wrapper"],"tags":["go","security","configuration","keyring"],"backgroundTag":"invalid-config-value","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}