crowdsecurity/crowdsec · error

ErrCookieTooLarge

ErrCookieTooLarge

Error message

%w: plaintext=%d > %d

What it means

Before marshaling, sealCookieV0 pre-computes the plaintext size (fixed 11-byte header + reason + protobuf envelope) and rejects anything exceeding the space available within maxCookieLen after base64 expansion, GCM nonce (12 bytes) and tag (16 bytes). The sentinel error is ErrCookieTooLarge. This guards against the 4 KB browser cookie limit and bounds attacker-influenced envelope allocation.

Source

Thrown at pkg/appsec/challenge/crypto.go:135

	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.
	maxPlaintext := maxCookieLen/4*3 - 1 - gcm.NonceSize() - gcm.Overhead()
	if plaintextLen := cookiePlaintextFixedHeaderLen + len(reason) + proto.Size(envelope); plaintextLen > maxPlaintext {
		return "", fmt.Errorf("%w: plaintext=%d > %d", ErrCookieTooLarge, plaintextLen, maxPlaintext)
	}

	envelopeBytes, err := proto.Marshal(envelope)
	if err != nil {
		return "", fmt.Errorf("failed to marshal challenge cookie proto: %w", err)
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err := rand.Read(nonce); err != nil {
		return "", fmt.Errorf("failed to generate nonce: %w", err)
	}

	// Build the plaintext: not_after_be8 || flags || reason_len_be || reason || envelope
	plaintext := make([]byte, 0, cookiePlaintextFixedHeaderLen+len(reason)+len(envelopeBytes))

	var notAfterBytes [8]byte
	binary.BigEndian.PutUint64(notAfterBytes[:], uint64(notAfter))
	plaintext = append(plaintext, notAfterBytes[:]...)

View on GitHub (pinned to 909b515798)

Solutions

  1. Raise the max_cookie_size challenge config value (default 4096) if the client tolerates larger cookies.
  2. Reduce the reason length (allowlist cookies) or slim the fingerprint envelope payload.
  3. Match errors.Is(err, challenge.ErrCookieTooLarge) to surface a clear 'cookie too large' message instead of a generic seal failure.

Example fix

# before
max_cookie_size: 2048
# after
max_cookie_size: 4096
Defensive patterns

Strategy: validation

Validate before calling

const maxCookieSize = 4096 // must be >= default; keep headroom for reason + envelope
if cfg.MaxCookieSize != nil && *cfg.MaxCookieSize < 4096 {
    log.Warn("max_cookie_size below default may reject valid fingerprint envelopes")
}

Try / catch

if err := errors.Is(err, challenge.ErrCookieTooLarge); err != nil {
    // raise max_cookie_size or trim reason/envelope, then retry once
}

Prevention

When it happens

Trigger: Calling sealCookieV0 with an envelope whose protobuf size plus reason length exceeds maxPlaintext = maxCookieLen/4*3 - 1 - 12 - 16; with default maxCookieLen 4096 that is ~3040 bytes. Reached via SealAllowlistCookie (large reason) or ValidateChallengeResponse (large fingerprint proto), or when max_cookie_size is configured lower than the payload.

Common situations: Deployments lowering max_cookie_size in appsec config below what the fingerprint envelope requires; unusually large fingerprint data (many attributes) stored in the envelope; an allowlist reason near the 256-byte cap combined with a big proto.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/e38a9a2c517a1c34. Report an issue: GitHub.