{"id":"f25c5e25ee35776e","repo":"jackc/pgx","slug":"invalid-scram-server-final-message-received-from-s","errorCode":null,"errorMessage":"invalid SCRAM server-final-message received from server","messagePattern":"invalid SCRAM server-final-message received from server","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgconn/auth_scram.go","lineNumber":335,"sourceCode":"\t}\n\tchannelBindingEncoded := base64.StdEncoding.EncodeToString(channelBindInput)\n\tclientFinalMessageWithoutProof := fmt.Appendf(nil, \"c=%s,r=%s\", channelBindingEncoded, sc.clientAndServerNonce)\n\n\tvar err error\n\tsc.saltedPassword, err = pbkdf2.Key(sha256.New, sc.password, sc.salt, sc.iterations, 32)\n\tif err != nil {\n\t\tpanic(err) // This should never happen.\n\t}\n\tsc.authMessage = bytes.Join([][]byte{sc.clientFirstMessageBare, sc.serverFirstMessage, clientFinalMessageWithoutProof}, []byte(\",\"))\n\n\tclientProof := computeClientProof(sc.saltedPassword, sc.authMessage)\n\n\treturn fmt.Sprintf(\"%s,p=%s\", clientFinalMessageWithoutProof, clientProof)\n}\n\nfunc (sc *scramClient) recvServerFinalMessage(serverFinalMessage []byte) error {\n\tif !bytes.HasPrefix(serverFinalMessage, []byte(\"v=\")) {\n\t\treturn errors.New(\"invalid SCRAM server-final-message received from server\")\n\t}\n\n\tserverSignature := serverFinalMessage[2:]\n\n\tif !hmac.Equal(serverSignature, computeServerSignature(sc.saltedPassword, sc.authMessage)) {\n\t\treturn errors.New(\"invalid SCRAM ServerSignature received from server\")\n\t}\n\n\treturn nil\n}\n\nfunc computeHMAC(key, msg []byte) []byte {\n\tmac := hmac.New(sha256.New, key)\n\tmac.Write(msg)\n\treturn mac.Sum(nil)\n}\n\nfunc computeClientProof(saltedPassword, authMessage []byte) []byte {","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgconn/auth_scram.go#L317-L353","documentation":"Returned by recvServerFinalMessage when the SCRAM server-final-message does not begin with 'v=' (the ServerSignature attribute). Per RFC 5802 the server-final-message is 'v=<signature>' optionally preceded by an 'e=' error attribute; pgx expects 'v=' here because auth errors arrive as ErrorResponse earlier.","triggerScenarios":"Server sends an AuthenticationSASLFinal whose payload lacks the 'v=' prefix. Indicates a malformed/tampered final message or a non-conformant server.","commonSituations":"Buggy server/proxy corrupting the final SASL message; MITM tampering; rare server bugs.","solutions":["Confirm the endpoint is genuine, conformant PostgreSQL.","Remove any SASL-rewriting middleware.","Capture the AuthenticationSASLFinal payload and report the malformed message."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := connect(); err != nil && strings.Contains(err.Error(), \"invalid SCRAM server-final-message\") {\n    return fmt.Errorf(\"malformed SCRAM final message from server: %w\", err)\n}","preventionTips":["Use sslmode=verify-full so the final message cannot be tampered with.","Avoid proxies that rewrite SASL payloads.","Capture AuthenticationSASLFinal bytes to localize the defect."],"tags":["authentication","scram","protocol","security"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}