crowdsecurity/crowdsec · error

failed to seal challenge cookie: %w

Error message

failed to seal challenge cookie: %w

What it means

After full validation, ValidateChallengeResponse seals an AppsecCookie under the master cookie key with an embedded not_after (cookieTTL) and the request's User-Agent. If sealCookieV0 fails, the error is wrapped as 'failed to seal challenge cookie' and no cookie can be issued even though the PoW itself succeeded.

Source

Thrown at pkg/appsec/challenge/challenge.go:725

			"is_bot":  fpData.FastBotDetection,
		}).Debug("validated submission")
	}

	// Seal the difficulty the client actually proved (MAC-authenticated above),
	// so the next request's re-challenge check compares against real work and an
	// escalated per-request difficulty survives the cookie round-trip.
	envelope := &pb.ChallengeCookie{
		Fingerprint:   fpData.ToProto(),
		PowDifficulty: int32(clientDifficulty),
	}

	// Seal under the long-lived master cookie key. The embedded not_after makes
	// the server validity window exactly c.cookieTTL (independent of key
	// rotation); the browser Max-Age below matches so both expire together.
	notAfter := time.Now().Add(c.cookieTTL).Unix()
	cookieValue, err := sealCookieV0(envelope, c.keys.MasterCookieKey(), notAfter, 0, "", []byte(request.UserAgent()), c.maxCookieLen)
	if err != nil {
		return nil, FingerprintData{}, 0, fmt.Errorf("failed to seal challenge cookie: %w", err)
	}

	ck := cookie.NewAppsecCookie(ChallengeCookieName).HttpOnly().Path("/").SameSite(cookie.SameSiteLax).ExpiresIn(c.cookieTTL).Value(cookieValue)
	if request.URL.Scheme == "https" {
		ck = ck.Secure()
	}

	return ck, fpData, clientDifficulty, nil
}

// SealAllowlistCookie mints an allowlist-bypass cookie (no fingerprint, with
// the operator reason) so GrantChallengeCookie can let trusted bots skip the
// challenge UI while still hitting on_challenge rules via fingerprint.Allowlisted.
// not_after honors c.cookieTTL unless ttlOverride (>0) is given; reason is
// bounded by MaxAllowlistReasonLen (crypto.go).
func (c *ChallengeRuntime) SealAllowlistCookie(request *http.Request, reason string, ttlOverride *time.Duration) (*cookie.AppsecCookie, error) {
	if c == nil {
		return nil, errors.New("challenge runtime not initialized")

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the AppSec configuration for a valid, non-empty cookie secret / key material and restart.
  2. Review the wrapped error: if it reports size, increase maxCookieLen or shorten cookie contents.
  3. If it appeared after a key-rotation change, verify keys.MasterCookieKey() is initialized before validation runs.
  4. Report upstream with the wrapped error if it reproduces with default config — it indicates an internal invariant bug.

Example fix

# before: appsec config missing cookie secret
appsec:
  challenge:
    cookie_ttl: 30s
# after: provide key material
appsec:
  challenge:
    cookie_ttl: 30s
    cookie_secret: <strong-random-secret>
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight in config loading: reject empty cookie key early
if len(keys.MasterCookieKey()) == 0 {
    return errors.New("appsec: master cookie key is empty; cannot seal challenge cookies")
}

Try / catch

cookie, fp, diff, err := rt.ValidateChallengeResponse(req, body)
if err != nil && strings.Contains(err.Error(), "seal challenge cookie") {
    logger.WithError(err).Error("cookie sealing failed; check cookie key config and maxCookieLen")
    http.Error(w, "internal error", http.StatusInternalServerError)
    return
}

Prevention

When it happens

Trigger: Calling ValidateChallengeResponse when sealCookieV0 returns an error — nil/invalid master cookie key, envelope serialization failure, cookie value exceeding maxCookieLen, or invalid inputs (empty key material after misconfiguration).

Common situations: Misconfigured or empty master cookie key in AppSec config; a User-Agent/cookie combination producing a sealed value longer than maxCookieLen (extremely long UA headers); internal key-rotation state corruption.

Related errors


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