crowdsecurity/crowdsec · error
invalid HMAC in challenge response
Error message
invalid HMAC in challenge response
What it means
HMAC verification failure inside ValidateChallengeResponse: the submitted sig does not equal HMAC(s, r||ts||n||f) with the derived secret, meaning the client did not hold the legitimate per-epoch secret. Same condition as the ErrChallengeHMAC sentinel, raised at the comparison site; maps to the 'hmac' failure reason.
Source
Thrown at pkg/appsec/challenge/challenge.go:677
// actually issued for this request, not the runtime-global default.
if clientDifficulty >= PowDifficultyImpossible {
return nil, FingerprintData{}, 0, ErrChallengeDifficulty
}
// Verify proof-of-work: SHA256(powSalt + nonce) must have required leading zero bits
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 {View on GitHub (pinned to 909b515798)
Solutions
- Deny or re-challenge the request; count repeated failures toward escalation
- Ensure all appsec instances validating responses share the same signing key and epoch rotation
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at pkg/appsec/challenge/challenge.go:677 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/71a86acfc0ba5125.
Report an issue: GitHub.