crowdsecurity/crowdsec · error
ErrCookiePayload
ErrCookiePayload
Error message
%w: %w
What it means
After extracting the allowlist reason, openCookieV0Bytes unmarshals the remaining plaintext bytes as a pb.ChallengeCookie protobuf. If proto.Unmarshal fails, the tail of the plaintext is not a valid ChallengeCookie message and the error is wrapped in ErrCookiePayload. This indicates an incompatible, truncated, or forged cookie payload.
Source
Thrown at pkg/appsec/challenge/crypto.go:268
if reasonLen > MaxAllowlistReasonLen {
return nil, fmt.Errorf("%w: reason_len=%d", ErrCookieMalformed, reasonLen)
}
if len(plaintext) < cookiePlaintextFixedHeaderLen+reasonLen {
return nil, fmt.Errorf("%w: plaintext shorter than declared reason_len", ErrCookieMalformed)
}
if notAfter <= now.Unix() {
return nil, fmt.Errorf("%w: not_after=%d now=%d", ErrCookieExpired, notAfter, now.Unix())
}
reasonStart := cookiePlaintextFixedHeaderLen
reasonEnd := reasonStart + reasonLen
reason := string(plaintext[reasonStart:reasonEnd])
envelope := &pb.ChallengeCookie{}
if err := proto.Unmarshal(plaintext[reasonEnd:], envelope); err != nil {
return nil, fmt.Errorf("%w: %w", ErrCookiePayload, err)
}
return &CookieEnvelope{
Envelope: envelope,
Allowlisted: flags&cookieFlagAllowlisted != 0,
AllowlistReason: reason,
NotAfter: notAfter,
}, nil
}
View on GitHub (pinned to 909b515798)
Solutions
- Regenerate the cookie from a matching (same-version) CrowdSec instance
- Ensure all instances sharing master_secret run compatible versions with identical ChallengeCookie proto definitions
- Do not attempt to parse attacker-controlled cookies further; treat as invalid and issue a new challenge
- If you control the issuer, re-seal with the current proto schema
Example fix
// before
env, err := rt.OpenCookie(raw, now)
if err != nil { http.Error(w, "bad cookie", 400) }
// after
if errors.Is(err, challenge.ErrCookiePayload) {
log.Debug().Err(err).Msg("invalid cookie payload; issuing new challenge")
return issueNewChallenge(w, r)
} Defensive patterns
Strategy: try-catch
Validate before calling
if errors.Is(err, challenge.ErrCookiePayload) { /* invalid payload */ } Type guard
func isCookiePayloadError(err error) bool { return errors.Is(err, challenge.ErrCookiePayload) } Try / catch
env, err := rt.OpenCookie(raw, now)
if errors.Is(err, challenge.ErrCookiePayload) {
log.Debug().Msg("invalid cookie payload; rejecting and re-issuing")
return issueNewChallenge()
} Prevention
- Deploy matching versions across all instances sharing a master secret
- Never parse attacker-supplied cookies beyond errors.Is classification
- Keep generated protobuf code in sync with the schema
- Reject cookies from unknown issuers early
When it happens
Trigger: openCookie is called with a cookie whose trailing bytes after the reason section are not a serialized pb.ChallengeCookie — e.g. produced by a binary with a different protobuf schema, or a truncated/forged cookie.
Common situations: Mixed CrowdSec versions where the cookie payload schema differs; cookies corrupted in transit or by storage; an attacker-supplied cookie value; a build where embedded protobuf definitions are out of sync.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- failed to marshal challenge cookie proto: %w
- appsec datasource requires a hub. this is a bug, please repo
- appsec datasource requires a lapi client configuration. this
- missing lapi client credentials
- no appsec_config provided
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/c10df5d585e7aada.
Report an issue: GitHub.