crowdsecurity/crowdsec · info
unknown cookie version
Error message
unknown cookie version
What it means
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.
Source
Thrown at pkg/appsec/challenge/crypto.go:32
"crypto/sha256"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"time"
"golang.org/x/crypto/hkdf"
"github.com/crowdsecurity/crowdsec/pkg/appsec/challenge/pb"
"google.golang.org/protobuf/proto"
)
var (
ErrCookieMalformed = errors.New("malformed cookie")
ErrCookieSignature = errors.New("invalid cookie signature")
ErrCookiePayload = errors.New("invalid cookie payload")
ErrCookieExpired = errors.New("cookie expired")
ErrCookieVersion = errors.New("unknown cookie version")
ErrAllowlistReasonSize = errors.New("allowlist reason exceeds maximum length")
ErrCookieTooLarge = errors.New("cookie exceeds maximum size")
)
const hkdfInfo = "crowdsec-challenge-cookie"
// MaxAllowlistReasonLen caps the reason string operators pass to
// GrantChallengeCookie. The reason travels inside every Set-Cookie + Cookie
// header round-trip until the cookie expires; bounding it keeps the cookie
// well under the 4 KB browser limit even with the AES-GCM tag + base64
// expansion.
const MaxAllowlistReasonLen = 256
// MaxCookieLen is the DEFAULT per-cookie size (RFC 6265 §6.1: 4096 bytes).
// Can be configured via Config.MaxCookieSize and we reject anything bigger.
const MaxCookieLen = 4096
// Cookie wire format. A single version byte at offset 0 lets us evolve theView on GitHub (pinned to 909b515798)
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.
Example fix
// before: opaque 500 on unrecognized cookie
resp := openCookie(raw)
// after: handle version mismatch with a fresh challenge
if errors.Is(err, challenge.ErrCookieVersion) {
return issueFreshChallenge()
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate cookie shape before trusting it: version byte must be known
if len(raw) == 0 {
return errors.New("empty cookie")
}
if raw[0] != 0x00 { // v0
return fmt.Errorf("unsupported cookie version 0x%02x", raw[0])
} Try / catch
if err := openCookie(raw, key, aad); err != nil {
if errors.Is(err, challenge.ErrCookieVersion) {
return issueFreshChallenge() // version skew: reissue
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- cookie expired
- failed to seal challenge cookie: %w
- failed to seal allowlist cookie: %w
- invalid challenge cookie: %w
- allowlist reason exceeds maximum length
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/b0b0328d7894ef07.
Report an issue: GitHub.