crowdsecurity/crowdsec · error
ErrChallengeDifficulty
ErrChallengeDifficulty
Error message
challenge difficulty is impossible
What it means
Sentinel error ErrChallengeDifficulty: the difficulty value submitted by the client in the challenge response is >= PowDifficultyImpossible, i.e. the client claims a difficulty so high it could never have been legitimately issued by the runtime — a sign of a tampered or replayed challenge payload. Mapped to the 'difficulty' failure reason in the appsec dispatcher metrics.
Source
Thrown at pkg/appsec/challenge/challenge.go:61
"golang.org/x/sync/singleflight"
"golang.org/x/sys/cpu"
)
// Internal URL paths the challenge runtime intercepts. Bouncers MUST forward
// these to the WAF unmodified; they are served by the appsec dispatcher
// (pkg/appsec/appsec.go) rather than by the protected origin.
const (
ChallengeJSPath = "/crowdsec-internal/challenge/challenge.js"
ChallengeSubmitPath = "/crowdsec-internal/challenge/submit"
ChallengePowWorkerPath = "/crowdsec-internal/challenge/pow-worker.js"
ChallengeFPScannerPath = "/crowdsec-internal/challenge/fpscanner.js"
)
// Sentinel errors (reasons) returned by ValidateChallengeResponse.
var (
ErrChallengeFields = errors.New("missing required fields in challenge response")
ErrChallengeTicket = errors.New("invalid ticket in challenge response")
ErrChallengeDifficulty = errors.New("challenge difficulty is impossible")
ErrChallengePoW = errors.New("invalid proof-of-work in challenge response")
ErrChallengeHMAC = errors.New("invalid HMAC in challenge response")
ErrChallengePayload = errors.New("invalid challenge response payload")
)
// ChallengeCookieName is the name of the sealed cookie carrying the
// successfully-validated fingerprint between requests.
const ChallengeCookieName = "__crowdsec_challenge"
// cryptoObfuscationPoolDefaultSize is how many obfuscations of the per-epoch
// key module to keep per live epoch. Each variant embeds the same key
// differently (per-visitor byte variance); default 1 keeps prior behavior.
const cryptoObfuscationPoolDefaultSize = 1
// defaultCookieTTL is the default challenge-cookie validity. Decoupled from the
// keyring window (enforced by not_after in the envelope), so cookies can
// outlive the per-epoch signing window without widening forgery exposure.
const defaultCookieTTL = 12 * time.HourView on GitHub (pinned to 909b515798)
Solutions
- Treat as a failed challenge: the request is denied or re-challenged per the appsec remediation config
- If false positives occur, verify the client's JS challenge module is up to date and that the difficulty in the issued ticket matches what the server validates
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at pkg/appsec/challenge/challenge.go:61 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/262bdbe777ce4b50.
Report an issue: GitHub.