crowdsecurity/crowdsec · error
ErrAllowlistReasonSize
ErrAllowlistReasonSize
Error message
%w: %d > %d
What it means
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.
Source
Thrown at pkg/appsec/challenge/crypto.go:114
return key, nil
}
// sealCookieV0 produces a v0 cookie sealed under the long-lived master
// cookie key. notAfter is the unix-seconds expiration; flags carries the
// allowlist bit set by GrantChallengeCookie (0 for normal cookies);
// reason is the operator-supplied allowlist reason (empty for normal
// cookies). All three are prepended to the marshaled proto BEFORE
// encryption so they are both confidential (not observable from the wire)
// and authenticated (any tamper attempt invalidates the GCM tag).
//
// Returns ErrAllowlistReasonSize if reason exceeds MaxAllowlistReasonLen.
func sealCookieV0(envelope *pb.ChallengeCookie, masterCookieKey []byte, notAfter int64, flags byte, reason string, aad []byte, maxCookieLen int) (string, error) {
if maxCookieLen <= 0 {
maxCookieLen = MaxCookieLen
}
if len(reason) > MaxAllowlistReasonLen {
return "", fmt.Errorf("%w: %d > %d", ErrAllowlistReasonSize, len(reason), MaxAllowlistReasonLen)
}
key, err := deriveKey(masterCookieKey)
if err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("failed to create cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("failed to create GCM: %w", err)
}
// Reject an over-limit envelope before marshaling it.View on GitHub (pinned to 909b515798)
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.
Example fix
// before
ck, err := rt.SealAllowlistCookie(req, longBanReason, nil)
// after
if len(longBanReason) > challenge.MaxAllowlistReasonLen {
longBanReason = longBanReason[:challenge.MaxAllowlistReasonLen]
}
ck, err := rt.SealAllowlistCookie(req, longBanReason, nil) Defensive patterns
Strategy: validation
Validate before calling
if len(reason) > challenge.MaxAllowlistReasonLen {
reason = reason[:challenge.MaxAllowlistReasonLen]
} Try / catch
ck, err := rt.SealAllowlistCookie(req, reason, nil)
if errors.Is(err, challenge.ErrAllowlistReasonSize) {
return http.StatusRequestEntityTooLarge
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Operators writing descriptive allowlist reasons (URLs, explanations, concatenated ticket references) into the allowlist grant API; automated integrations echoing ban descriptions as reasons.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- allowlist reason exceeds maximum length
- cookie exceeds maximum size
- invalid challenge cookie: %w
- ErrCookieTooLarge
- invalid schema name
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/70f9c0bd2c3cb4aa.
Report an issue: GitHub.