{"record":{"id":"71a86acfc0ba5125","repo":"crowdsecurity/crowdsec","slug":"invalid-hmac-in-challenge-response","errorCode":null,"errorMessage":"invalid HMAC in challenge response","messagePattern":"invalid HMAC in challenge response","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/appsec/challenge/challenge.go","lineNumber":677,"sourceCode":"\t// actually issued for this request, not the runtime-global default.\n\tif clientDifficulty >= PowDifficultyImpossible {\n\t\treturn nil, FingerprintData{}, 0, ErrChallengeDifficulty\n\t}\n\n\t// Verify proof-of-work: SHA256(powSalt + nonce) must have required leading zero bits\n\tpowHash := sha256.Sum256([]byte(clientPowSalt + clientNonce))\n\tif !hasLeadingZeroBits(powHash[:], clientDifficulty) {\n\t\treturn nil, FingerprintData{}, 0, ErrChallengePoW\n\t}\n\n\t// Verify the submission signature sig = HMAC(s, r||ts||n||f), where the\n\t// secret s = HMAC(K_epoch, r) is never transmitted — a valid sig proves the\n\t// client derived s from the per-epoch key in the obfuscated dynamic module.\n\ts := deriveChallengeSecret(signKey, clientR)\n\n\texpectedSig := hmacSHA256Hex([]byte(s), []byte(clientR+clientTS+clientNonce+encryptedFingerprint))\n\tif !hmac.Equal([]byte(clientSig), []byte(expectedSig)) {\n\t\treturn nil, FingerprintData{}, 0, errors.New(\"invalid HMAC in challenge response\")\n\t}\n\n\t// Single-use: burn `r` (rejects replays). Done last so the spent-set only\n\t// grows on fully-valid submissions.\n\tif !c.spent.checkAndInsert(clientR, ticketAgeBackstop) {\n\t\treturn nil, FingerprintData{}, 0, errors.New(\"challenge response already used\")\n\t}\n\n\tobfKey := deriveFingerprintObfKey(s, clientR)\n\n\tfingerprint, err := deobfuscateFingerprint(obfKey, encryptedFingerprint)\n\tif err != nil {\n\t\treturn nil, FingerprintData{}, 0, fmt.Errorf(\"failed to deobfuscate fingerprint: %w\", err)\n\t}\n\n\tvar fpData FingerprintData\n\n\tif err := json.Unmarshal([]byte(fingerprint), &fpData); err != nil {","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/challenge.go#L659-L695","documentation":"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.","triggerScenarios":"Thrown at pkg/appsec/challenge/challenge.go:677 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}