{"record":{"id":"70f9c0bd2c3cb4aa","repo":"crowdsecurity/crowdsec","slug":"errallowlistreasonsize","errorCode":"ErrAllowlistReasonSize","errorMessage":"%w: %d > %d","messagePattern":"%w: (.+?) > (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/appsec/challenge/crypto.go","lineNumber":114,"sourceCode":"\treturn key, nil\n}\n\n// sealCookieV0 produces a v0 cookie sealed under the long-lived master\n// cookie key. notAfter is the unix-seconds expiration; flags carries the\n// allowlist bit set by GrantChallengeCookie (0 for normal cookies);\n// reason is the operator-supplied allowlist reason (empty for normal\n// cookies). All three are prepended to the marshaled proto BEFORE\n// encryption so they are both confidential (not observable from the wire)\n// and authenticated (any tamper attempt invalidates the GCM tag).\n//\n// Returns ErrAllowlistReasonSize if reason exceeds MaxAllowlistReasonLen.\nfunc sealCookieV0(envelope *pb.ChallengeCookie, masterCookieKey []byte, notAfter int64, flags byte, reason string, aad []byte, maxCookieLen int) (string, error) {\n\tif maxCookieLen <= 0 {\n\t\tmaxCookieLen = MaxCookieLen\n\t}\n\n\tif len(reason) > MaxAllowlistReasonLen {\n\t\treturn \"\", fmt.Errorf(\"%w: %d > %d\", ErrAllowlistReasonSize, len(reason), MaxAllowlistReasonLen)\n\t}\n\n\tkey, err := deriveKey(masterCookieKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create cipher: %w\", err)\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create GCM: %w\", err)\n\t}\n\n\t// Reject an over-limit envelope before marshaling it.","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/crypto.go#L96-L132","documentation":"sealCookieV0 rejects allowlist reasons longer than MaxAllowlistReasonLen (256 bytes) before sealing, because the reason rides inside every Set-Cookie/Cookie round-trip until expiration and must keep the cookie under the 4 KB browser limit. The sentinel error is ErrAllowlistReasonSize, reported with the actual vs. maximum lengths.","triggerScenarios":"Calling SealAllowlistCookie/GrantChallengeCookie (or sealCookieV0 directly) with a reason string whose byte length exceeds 256; ValidateChallengeResponse and normal cookie sealing are unaffected since they pass an empty reason.","commonSituations":"Operators writing descriptive allowlist reasons (URLs, explanations, concatenated ticket references) into the allowlist grant API; automated integrations echoing ban descriptions as reasons.","solutions":["Truncate or shorten the reason to 256 bytes or fewer before calling SealAllowlistCookie.","Compare errors.Is(err, challenge.ErrAllowlistReasonSize) to detect this case specifically and return a clear 4xx to the operator.","Store long explanations out-of-band (database, ticket system) and keep only a short identifier in the cookie reason."],"exampleFix":"// before\nck, err := rt.SealAllowlistCookie(req, longBanReason, nil)\n// after\nif len(longBanReason) > challenge.MaxAllowlistReasonLen {\n    longBanReason = longBanReason[:challenge.MaxAllowlistReasonLen]\n}\nck, err := rt.SealAllowlistCookie(req, longBanReason, nil)","handlingStrategy":"validation","validationCode":"if len(reason) > challenge.MaxAllowlistReasonLen {\n    reason = reason[:challenge.MaxAllowlistReasonLen]\n}","typeGuard":null,"tryCatchPattern":"ck, err := rt.SealAllowlistCookie(req, reason, nil)\nif errors.Is(err, challenge.ErrAllowlistReasonSize) {\n    return http.StatusRequestEntityTooLarge\n}","preventionTips":["Cap reason length at the ingest point (API handler, LAPI route).","Reference tickets by ID, not full description.","Test the boundary: 256 bytes must pass, 257 must fail."],"tags":["appsec","cookie","validation","input-length"],"backgroundTag":"value-out-of-range","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"}