{"record":{"id":"dfb6a16724f8c582","repo":"crowdsecurity/crowdsec","slug":"failed-to-decode-obfuscated-fingerprint-w","errorCode":null,"errorMessage":"failed to decode obfuscated fingerprint: %w","messagePattern":"failed to decode obfuscated fingerprint: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/appsec/challenge/ticket.go","lineNumber":161,"sourceCode":"\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// deriveFingerprintObfKey returns the keystream key for the fingerprint\n// payload: `HMAC(s, \"fpenc\"||r)`.\nfunc deriveFingerprintObfKey(s, r string) string {\n\treturn hmacSHA256Hex([]byte(s), []byte(\"fpenc\"+r))\n}\n\n// deobfuscateFingerprint reverses the client-side repeating-key XOR + base64\n// applied to the fingerprint JSON, using the key from deriveFingerprintObfKey.\nfunc deobfuscateFingerprint(obfKey string, payload string) (string, error) {\n\tpayloadBytes, err := base64.StdEncoding.DecodeString(payload)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to decode obfuscated fingerprint: %w\", err)\n\t}\n\n\tout := make([]byte, len(payloadBytes))\n\n\tfor i := range payloadBytes {\n\t\tout[i] = payloadBytes[i] ^ obfKey[i%len(obfKey)]\n\t}\n\n\treturn string(out), nil\n}\n\n// verifyChallenge gates timestamp freshness and authenticates the PoW-salt\n// binding, returning the per-epoch sign key (for deriving `s`) on success.\n// Stateless — any instance sharing the master secret can verify. Knowledge of\n// the per-epoch key is proven separately by the caller's `sig` check.\nfunc (c *ChallengeRuntime) verifyChallenge(clientR, clientTS, clientPowSalt, clientPowMAC string, clientDifficulty int) ([]byte, bool) {\n\ttsVal, err := strconv.ParseInt(clientTS, 10, 64)\n\tif err != nil || tsVal <= 0 {","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/appsec/challenge/ticket.go#L143-L179","documentation":"deobfuscateFingerprint base64-decodes the client-supplied fingerprint blob (repeating-key XOR + base64 applied client-side) before validating the challenge response. This error means the payload is not valid standard base64, i.e. the client sent malformed or tampered fingerprint data.","triggerScenarios":"ValidateChallengeResponse receives a fingerprint payload that fails base64.StdEncoding.DecodeString — the bouncer/client sent a corrupted, truncated, or non-base64 obfuscated fingerprint, or encrypted it with a different scheme than the server expects.","commonSituations":"Version mismatch between client-side challenge JS/bouncer and server (obfuscation scheme changed), intermediaries mangling the POST body, or a malicious/broken client submitting garbage instead of the computed fingerprint.","solutions":["Check that the client-side challenge script and crowdsec appsec component are the same version (obfuscation key/scheme must match)","Log the raw payload and verify it is valid standard base64 (padding, charset)","Rule out proxies/WAFs rewriting the request body (re-encoding, chunk mangling)","If you wrote the client, confirm you XOR with the same key and use StdEncoding (not URL/raw encoding) before sending"],"exampleFix":"// before (client, JavaScript)\nconst payload = btoa(xored)\n// after — use URL-safe-free standard base64 matching Go StdEncoding, ensure binary-safe XOR bytes\nconst payload = btoa(String.fromCharCode(...xoredBytes))","handlingStrategy":"validation","validationCode":"if _, err := base64.StdEncoding.DecodeString(payload); err != nil {\n    // reject before calling validation\n}","typeGuard":null,"tryCatchPattern":"fp, err := deobfuscateFingerprint(obfKey, payload)\nif err != nil {\n    log.Debugf(\"bad fingerprint payload: %v\", err)\n    return challengeFailed\n}","preventionTips":["Keep challenge client script and server in version lockstep","Validate payloads are base64 at the edge before processing","Test through any proxy chain that might rewrite bodies"],"tags":["appsec","base64","fingerprint","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}