{"record":{"id":"b0b0328d7894ef07","repo":"crowdsecurity/crowdsec","slug":"unknown-cookie-version","errorCode":null,"errorMessage":"unknown cookie version","messagePattern":"unknown cookie version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"pkg/appsec/challenge/crypto.go","lineNumber":32,"sourceCode":"\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"golang.org/x/crypto/hkdf\"\n\n\t\"github.com/crowdsecurity/crowdsec/pkg/appsec/challenge/pb\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\nvar (\n\tErrCookieMalformed     = errors.New(\"malformed cookie\")\n\tErrCookieSignature     = errors.New(\"invalid cookie signature\")\n\tErrCookiePayload       = errors.New(\"invalid cookie payload\")\n\tErrCookieExpired       = errors.New(\"cookie expired\")\n\tErrCookieVersion       = errors.New(\"unknown cookie version\")\n\tErrAllowlistReasonSize = errors.New(\"allowlist reason exceeds maximum length\")\n\tErrCookieTooLarge      = errors.New(\"cookie exceeds maximum size\")\n)\n\nconst hkdfInfo = \"crowdsec-challenge-cookie\"\n\n// MaxAllowlistReasonLen caps the reason string operators pass to\n// GrantChallengeCookie. The reason travels inside every Set-Cookie + Cookie\n// header round-trip until the cookie expires; bounding it keeps the cookie\n// well under the 4 KB browser limit even with the AES-GCM tag + base64\n// expansion.\nconst MaxAllowlistReasonLen = 256\n\n// MaxCookieLen is the DEFAULT per-cookie size (RFC 6265 §6.1: 4096 bytes).\n// Can be configured via Config.MaxCookieSize and we reject anything bigger.\nconst MaxCookieLen = 4096\n\n// Cookie wire format. A single version byte at offset 0 lets us evolve the","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/crypto.go#L14-L50","documentation":"ErrCookieVersion signals that a presented cookie's first byte (version prefix) is not a version this build understands (only 0x00/v0 currently). openCookie dispatches on raw[0] and wraps the sentinel with the offending byte in hex. This lets the appsec layer respond with \"epoch\" (fresh challenge) rather than failing closed ambiguously, and leaves room for future cookie formats.","triggerScenarios":"openCookie receives a cookie whose version byte is not 0; e.g. corrupted cookie, truncated value, or a cookie produced by a newer/older crowdsec with a different cookie format version. Returned by openCookie and asserted in TestCookie_UnknownVersionRejected.","commonSituations":"Version skew between rolling-updated crowdsec nodes sharing a master key; garbage appended to the cookie by a proxy; a user hand-editing or truncating the cookie value.","solutions":["Ensure all crowdsec/LAPI nodes run the same version so cookie formats match.","Clear the client's cookie — the server responds with a fresh challenge (\"epoch\" remediation).","If it reproduces from a freshly issued cookie, check for middleware/proxies mangling the Cookie header (encoding, length limits).","Verify the master key / build is not from a divergent fork producing different cookie bytes."],"exampleFix":"// before: opaque 500 on unrecognized cookie\nresp := openCookie(raw)\n// after: handle version mismatch with a fresh challenge\nif errors.Is(err, challenge.ErrCookieVersion) {\n    return issueFreshChallenge()\n}","handlingStrategy":"try-catch","validationCode":"// validate cookie shape before trusting it: version byte must be known\nif len(raw) == 0 {\n    return errors.New(\"empty cookie\")\n}\nif raw[0] != 0x00 { // v0\n    return fmt.Errorf(\"unsupported cookie version 0x%02x\", raw[0])\n}","typeGuard":null,"tryCatchPattern":"if err := openCookie(raw, key, aad); err != nil {\n    if errors.Is(err, challenge.ErrCookieVersion) {\n        return issueFreshChallenge() // version skew: reissue\n    }\n    return err\n}","preventionTips":["Keep all crowdsec nodes on the same version during rolling upgrades","Never hand-edit cookie values client-side","Guard against proxies rewriting/mangling Cookie headers","When introducing a new cookie version, keep accepting older ones or force reissue"],"tags":["appsec","cookie","versioning","crypto"],"backgroundTag":"unsupported-enum-value","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"}