{"record":{"id":"7d50440af11dbfd8","repo":"crowdsecurity/crowdsec","slug":"failed-to-seal-allowlist-cookie-w","errorCode":null,"errorMessage":"failed to seal allowlist cookie: %w","messagePattern":"failed to seal allowlist cookie: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/appsec/challenge/challenge.go","lineNumber":754,"sourceCode":"// SealAllowlistCookie mints an allowlist-bypass cookie (no fingerprint, with\n// the operator reason) so GrantChallengeCookie can let trusted bots skip the\n// challenge UI while still hitting on_challenge rules via fingerprint.Allowlisted.\n// not_after honors c.cookieTTL unless ttlOverride (>0) is given; reason is\n// bounded by MaxAllowlistReasonLen (crypto.go).\nfunc (c *ChallengeRuntime) SealAllowlistCookie(request *http.Request, reason string, ttlOverride *time.Duration) (*cookie.AppsecCookie, error) {\n\tif c == nil {\n\t\treturn nil, errors.New(\"challenge runtime not initialized\")\n\t}\n\n\tttl := c.cookieTTL\n\tif ttlOverride != nil && *ttlOverride > 0 {\n\t\tttl = *ttlOverride\n\t}\n\n\tnotAfter := time.Now().Add(ttl).Unix()\n\tcookieValue, err := sealCookieV0(&pb.ChallengeCookie{}, c.keys.MasterCookieKey(), notAfter, cookieFlagAllowlisted, reason, []byte(request.UserAgent()), c.maxCookieLen)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to seal allowlist cookie: %w\", err)\n\t}\n\n\tck := cookie.NewAppsecCookie(ChallengeCookieName).HttpOnly().Path(\"/\").SameSite(cookie.SameSiteLax).ExpiresIn(ttl).Value(cookieValue)\n\tif request.URL.Scheme == \"https\" {\n\t\tck = ck.Secure()\n\t}\n\n\treturn ck, nil\n}\n\n// CookieData bundles the decoded fingerprint with cookie-envelope metadata for\n// re-challenge decisions. Allowlisted/AllowlistReason mark cookies minted by\n// SealAllowlistCookie; they are zero for real-submission cookies.\ntype CookieData struct {\n\tFingerprint     FingerprintData\n\tPowDifficulty   int\n\tAllowlisted     bool\n\tAllowlistReason string","sourceCodeStart":736,"sourceCodeEnd":772,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/challenge.go#L736-L772","documentation":"SealAllowlistCookie mints an AES-GCM-sealed allowlist-bypass challenge cookie, encrypting the envelope under the master cookie key. This wrapper error means the underlying sealCookieV0 call failed, so no allowlist cookie could be produced and GrantChallengeCookie cannot grant the bypass. It always wraps one of the crypto-layer errors: reason too long, proto marshal failure, size-limit breach, or entropy failure.","triggerScenarios":"Calling ChallengeRuntime.SealAllowlistCookie (via GrantChallengeCookie) with an operator reason longer than MaxAllowlistReasonLen (256 bytes), or when the resulting plaintext exceeds the configured max cookie size, or an internal crypto/entropy failure.","commonSituations":"Operators passing a long human-readable allowlist reason (e.g. a URL, ticket ID, or description) through the allowlist API; deployments with a reduced max_cookie_size config value sealing larger envelopes.","solutions":["Shorten the reason string passed to SealAllowlistCookie/GrantChallengeCookie to at most 256 bytes.","If ErrCookieTooLarge is wrapped, raise the max_cookie_size challenge config value or reduce the cookie payload.","Check the wrapped error (%w chain) to identify the exact crypto-layer cause; entropy failures (rand.Read) indicate a broken system CSPRNG.","Verify the runtime was initialized (nil runtime returns a different error, but a half-initialized keyring is worth ruling out)."],"exampleFix":"// before\nck, err := rt.SealAllowlistCookie(req, \"allowlisted for support ticket #4821 - trusted corporate proxy scanning partner integration from the security operations center\", nil)\n// after\nreason := \"support ticket #4821 - trusted proxy\"\nif len(reason) > challenge.MaxAllowlistReasonLen {\n    reason = reason[:challenge.MaxAllowlistReasonLen]\n}\nck, err := rt.SealAllowlistCookie(req, reason, nil)","handlingStrategy":"validation","validationCode":"if len(reason) > challenge.MaxAllowlistReasonLen {\n    return fmt.Errorf(\"allowlist reason too long: %d > %d\", len(reason), challenge.MaxAllowlistReasonLen)\n}","typeGuard":null,"tryCatchPattern":"if _, err := rt.SealAllowlistCookie(req, reason, nil); err != nil {\n    if errors.Is(err, challenge.ErrAllowlistReasonSize) { /* truncate reason and retry */ }\n    return err\n}","preventionTips":["Clamp reason strings at the API boundary before granting allowlist cookies.","Keep allowlist reasons to short identifiers, not descriptions.","Cover GrantChallengeCookie with a test using a 257-byte reason."],"tags":["appsec","crypto","cookie","challenge"],"backgroundTag":"encryption-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}