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

  1. Deny or re-challenge the request; count repeated failures toward escalation
  2. 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.