{"record":{"id":"a6f1302192846f39","repo":"kubernetes/kops","slug":"callback-challenge-returned-wrong-result","errorCode":null,"errorMessage":"callback challenge returned wrong result","messagePattern":"callback challenge returned wrong result","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/bootstrap/challenge_client.go","lineNumber":126,"sourceCode":"\n\texpectedChallengeResponse := buildChallengeResponse(challenge.ChallengeSecret, kospControllerNonce)\n\n\tvar opts []grpc.DialOption\n\topts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))\n\tconn, err := grpc.DialContext(ctx, targetEndpoint, opts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing target %q: %w\", targetEndpoint, err)\n\t}\n\tdefer conn.Close()\n\tclient := pb.NewCallbackServiceClient(conn)\n\n\tresponse, err := client.Challenge(ctx, req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error from callback challenge: %w\", err)\n\t}\n\n\tif subtle.ConstantTimeCompare(response.GetChallengeResponse(), expectedChallengeResponse) != 1 {\n\t\treturn fmt.Errorf(\"callback challenge returned wrong result\")\n\t}\n\treturn nil\n}\n","sourceCodeStart":108,"sourceCodeEnd":130,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/bootstrap/challenge_client.go#L108-L130","documentation":"After a successful RPC, the client compares the server's response bytes to the locally computed expected challenge response using a constant-time comparison. A mismatch means the server returned a different response than the HMAC derived from the ChallengeSecret — indicating the server did not hold the same secret or the challenge data was tampered with.","triggerScenarios":"Calling DoCallbackChallenge when response.GetChallengeResponse() differs from buildChallengeResponse(ChallengeSecret, nonce): wrong/rotated secret on the server, stale challenge ID, or a man-in-the-middle/buggy server returning unexpected bytes.","commonSituations":"The challenge secret was rotated on the server after issuance to the node; the node cached an old challenge; a misconfigured or malicious callback endpoint answering with wrong material.","solutions":["Re-run the challenge/bootstrap flow to obtain a fresh challenge and secret from kops-controller","Verify the ChallengeID and ChallengeSecret pair matches what the server currently holds","Ensure you are dialing the genuine kops-controller endpoint, not a stale or spoofed address"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"if len(ch.ChallengeID) == 0 || len(ch.ChallengeSecret) == 0 {\n\treturn fmt.Errorf(\"stale/empty challenge; request a fresh challenge first\")\n}","typeGuard":null,"tryCatchPattern":"if err := client.DoCallbackChallenge(ctx, clusterName, ch); err != nil {\n\tif strings.Contains(err.Error(), \"wrong result\") {\n\t\t// discard cached challenge, re-request a fresh one, retry once\n\t}\n\treturn err\n}","preventionTips":["Never cache challenge secrets across rotations","Always dial the canonical kops-controller endpoint","Re-run the challenge handshake on any mismatch instead of retrying the same data"],"tags":["security","challenge-response","hmac","verification"],"backgroundTag":"challenge-response-mismatch","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}