crowdsecurity/crowdsec · error
challenge response already used
Error message
challenge response already used
What it means
Replay protection failure in ValidateChallengeResponse: the nonce/ticket material in this response has already been consumed (single-use enforcement), so an identical or replayed submission is rejected.
Source
Thrown at pkg/appsec/challenge/challenge.go:683
powHash := sha256.Sum256([]byte(clientPowSalt + clientNonce))
if !hasLeadingZeroBits(powHash[:], clientDifficulty) {
return nil, FingerprintData{}, 0, ErrChallengePoW
}
// Verify the submission signature sig = HMAC(s, r||ts||n||f), where the
// secret s = HMAC(K_epoch, r) is never transmitted — a valid sig proves the
// client derived s from the per-epoch key in the obfuscated dynamic module.
s := deriveChallengeSecret(signKey, clientR)
expectedSig := hmacSHA256Hex([]byte(s), []byte(clientR+clientTS+clientNonce+encryptedFingerprint))
if !hmac.Equal([]byte(clientSig), []byte(expectedSig)) {
return nil, FingerprintData{}, 0, errors.New("invalid HMAC in challenge response")
}
// Single-use: burn `r` (rejects replays). Done last so the spent-set only
// grows on fully-valid submissions.
if !c.spent.checkAndInsert(clientR, ticketAgeBackstop) {
return nil, FingerprintData{}, 0, errors.New("challenge response already used")
}
obfKey := deriveFingerprintObfKey(s, clientR)
fingerprint, err := deobfuscateFingerprint(obfKey, encryptedFingerprint)
if err != nil {
return nil, FingerprintData{}, 0, fmt.Errorf("failed to deobfuscate fingerprint: %w", err)
}
var fpData FingerprintData
if err := json.Unmarshal([]byte(fingerprint), &fpData); err != nil {
return nil, FingerprintData{}, 0, fmt.Errorf("%w: failed to unmarshal fingerprint data: %w", ErrChallengePayload, err)
}
// Debug diagnostic: a validated submission. Guarded so `k_epoch` (forgeable
// signing material — DESIGN.md §2.1) is only formatted at debug.
if c.log().Logger.IsLevelEnabled(log.DebugLevel) {View on GitHub (pinned to 909b515798)
Solutions
- Treat as replay: deny the request and consider escalating remediation for repeated replays
- Investigate caching layers (CDN, proxy) that might resubmit a previously served challenge response
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at pkg/appsec/challenge/challenge.go:683 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/f4ba44f96a1bc300.
Report an issue: GitHub.