{"record":{"id":"e72cd05ae8ce9025","repo":"crowdsecurity/crowdsec","slug":"invalid-challenge-cookie-w","errorCode":null,"errorMessage":"invalid challenge cookie: %w","messagePattern":"invalid challenge cookie: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/appsec/challenge/challenge.go","lineNumber":787,"sourceCode":"\tFingerprint     FingerprintData\n\tPowDifficulty   int\n\tAllowlisted     bool\n\tAllowlistReason string\n}\n\n// ValidCookie unseals and validates a challenge cookie: envelope (version,\n// AES-GCM tag), not_after expiry, and UA-pinning (a stolen cookie is useless to\n// a different client). On any failure (tampered/expired/UA-mismatch/unknown\n// version) it returns an error and the caller should treat the request as\n// cookieless.\nfunc (c *ChallengeRuntime) ValidCookie(ck *http.Cookie, userAgent string) (*CookieData, error) {\n\tif ck == nil {\n\t\treturn nil, errors.New(\"nil cookie\")\n\t}\n\n\tenvelope, err := openCookie(ck.Value, c.keys.MasterCookieKey(), []byte(userAgent), c.maxCookieLen)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid challenge cookie: %w\", err)\n\t}\n\n\treturn &CookieData{\n\t\tFingerprint:     fingerprintDataFromProto(envelope.Envelope.GetFingerprint()),\n\t\tPowDifficulty:   int(envelope.Envelope.GetPowDifficulty()),\n\t\tAllowlisted:     envelope.Allowlisted,\n\t\tAllowlistReason: envelope.AllowlistReason,\n\t}, nil\n}\n","sourceCodeStart":769,"sourceCodeEnd":797,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/challenge.go#L769-L797","documentation":"ValidCookie unseals and validates the client's challenge cookie (AES-GCM envelope integrity, expiration, user-agent pinning). This wrapper means openCookie rejected the cookie for any reason: malformed base64, bad GCM signature, expired not_after, unknown version, oversized value, or a user-agent mismatch breaking the AEAD authentication.","triggerScenarios":"Calling ChallengeRuntime.ValidCookie(cookie, userAgent) with a cookie that is expired (not_after <= now), tampered with, sealed under a different master_secret, sent from a different User-Agent than when minted, corrupt, larger than maxCookieLen, or using an unknown version byte.","commonSituations":"Client browsers holding a cookie older than cookie_ttl (default 12h); load-balanced fleets where instances have different master_secret values; cookie replayed from a different browser/UA than the one that solved the challenge; shared master_secret rotated on only some nodes; stale cookies surviving an application restart when master_secret is ephemeral.","solutions":["Treat this as 'no valid cookie': the caller should serve the challenge again rather than error out to the client.","Ensure all instances in a distributed deployment share the identical master_secret config value.","Check whether the User-Agent differs between cookie mint and validation; the UA is AAD-pinned to the cookie.","Confirm the cookie is within cookie_ttl; expired cookies must be re-minted by solving the challenge.","If errors appear fleet-wide after a restart, configure a persistent master_secret so cookies survive restarts."],"exampleFix":"ck, err := r.Cookie(challenge.ChallengeCookieName)\nif err != nil {\n    return serveChallenge(w, req)\n}\ncd, err := rt.ValidCookie(ck, req.UserAgent())\nif err != nil {\n    log.Debug().Err(err).Msg(\"invalid challenge cookie, re-challenging\")\n    return serveChallenge(w, req)\n}","handlingStrategy":"fallback","validationCode":"if ck == nil || ck.Value == \"\" || len(ck.Value) > challenge.MaxCookieLen {\n    return serveChallenge(w, req)\n}","typeGuard":"func validChallengeCookie(ck *http.Cookie) bool { return ck != nil && ck.Value != \"\" && len(ck.Value) <= challenge.MaxCookieLen }","tryCatchPattern":"cd, err := rt.ValidCookie(ck, req.UserAgent())\nif err != nil {\n    log.Debug().Err(err).Msg(\"invalid challenge cookie; serving challenge\")\n    return serveChallenge(w, req)\n}","preventionTips":["Set one identical master_secret across all fleet instances.","Set a persistent master_secret so cookies survive restarts.","Expect UA-pinning: never validate a cookie against a rewritten User-Agent.","Treat cookie errors as 'no cookie' and re-challenge, not as fatal."],"tags":["appsec","crypto","cookie","validation"],"backgroundTag":"invalid-cookie-signature","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}