{"id":"8d9e0f00a1f17982","repo":"jackc/pgx","slug":"invalid-scram-serversignature-received-from-server","errorCode":null,"errorMessage":"invalid SCRAM ServerSignature received from server","messagePattern":"invalid SCRAM ServerSignature received from server","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pgconn/auth_scram.go","lineNumber":341,"sourceCode":"\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 {\n\tclientKey := computeHMAC(saltedPassword, []byte(\"Client Key\"))\n\tstoredKey := sha256.Sum256(clientKey)\n\tclientSignature := computeHMAC(storedKey[:], authMessage)\n\n\tclientProof := make([]byte, len(clientSignature))\n\tfor i := range clientSignature {","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgconn/auth_scram.go#L323-L359","documentation":"Returned by recvServerFinalMessage when the server's 'v=' ServerSignature does not match the HMAC the client computes from the derived ServerKey. SCRAM uses this to let the CLIENT authenticate the SERVER: a mismatch means the server does not hold the credentials corresponding to this password. Against genuine PostgreSQL this strongly suggests a man-in-the-middle that cannot compute the valid signature.","triggerScenarios":"After sending the client-final-message, the server's returned signature fails hmac.Equal against computeServerSignature(saltedPassword, authMessage). Happens when a MITM relayed the handshake but cannot recompute the proof, or when the exchange was tampered with after the client proof was computed.","commonSituations":"TLS with InsecureSkipVerify (sslmode=prefer/require without root cert) allowing a MITM; a rogue proxy presenting as the DB; extremely rarely, memory corruption. Note: a WRONG password yields a server ErrorResponse, not this error.","solutions":["Use sslmode=verify-full with a correct sslrootcert so the server identity is authenticated, preventing MITM.","Remove any TLS-terminating proxy or ensure it does not reoriginate the connection.","Investigate as a potential MITM/security incident; verify the server certificate chain and hostname."],"exampleFix":"// before: vulnerable to MITM\nconnStr := \"host=db user=app sslmode=require\"\n\n// after: full verification prevents the signature mismatch\nconnStr := \"host=db user=app sslmode=verify-full sslrootcert=/etc/ssl/db-ca.pem\"","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// ServerSignature mismatch means the server could not prove it holds the credentials.\nif err := connect(); err != nil && strings.Contains(err.Error(), \"invalid SCRAM ServerSignature\") {\n    securityLog.Error(\"SCRAM server signature mismatch: likely MITM on an unverified TLS channel\", \"err\", err)\n    return errors.Join(err, errPossibleMITM)\n}","preventionTips":["Always use sslmode=verify-full with the correct sslrootcert; never sslmode=require without a root cert for sensitive data.","Eliminate TLS-terminating proxies that reoriginate the DB connection.","Treat signature mismatches as security incidents and audit the network path."],"tags":["authentication","scram","security","mitm","tls"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}