{"id":"21a0a05644ec8c02","repo":"brianc/node-postgres","slug":"sasl-scram-server-first-message-server-nonce-doe","errorCode":null,"errorMessage":"SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce","messagePattern":"SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":79,"sourceCode":"\nasync function continueSession(session, password, serverData, stream) {\n  if (session.message !== 'SASLInitialResponse') {\n    throw new Error('SASL: Last message was not SASLInitialResponse')\n  }\n  if (typeof password !== 'string') {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')\n  }\n  if (password === '') {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a non-empty string')\n  }\n  if (typeof serverData !== 'string') {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: serverData must be a string')\n  }\n\n  const sv = parseServerFirstMessage(serverData)\n\n  if (!sv.nonce.startsWith(session.clientNonce)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce')\n  } else if (sv.nonce.length === session.clientNonce.length) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce is too short')\n  }\n\n  const scramMaxIterations =\n    typeof session.scramMaxIterations === 'number' ? session.scramMaxIterations : DEFAULT_MAX_SCRAM_ITERATIONS\n  // a value of 0 disables the iteration count check\n  if (scramMaxIterations !== 0 && sv.iteration > scramMaxIterations) {\n    throw new Error(\n      'SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration count ' +\n        sv.iteration +\n        ' exceeds scramMaxIterations of ' +\n        scramMaxIterations\n    )\n  }\n\n  const clientFirstMessageBare = 'n=*,r=' + session.clientNonce\n  const serverFirstMessage = 'r=' + sv.nonce + ',s=' + sv.salt + ',i=' + sv.iteration","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/brianc/node-postgres/blob/c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711/packages/pg/lib/crypto/sasl.js#L61-L97","documentation":"Thrown during SCRAM session continuation (sasl.js:78-79) when the server's combined nonce (r=...) does not begin with the client's nonce. Per RFC 5802, the server must return the client nonce unchanged with its own nonce appended; a server nonce that does not start with the client nonce indicates either a protocol violation or a potential man-in-the-middle/replay attack where the server response was substituted. The client sent r=<clientNonce> in the first message and verifies the server echoed it back as a prefix.","triggerScenarios":"The server's first SCRAM message contains an r= value whose first bytes do not match the clientNonce generated at sasl.js:50. This is checked via sv.nonce.startsWith(session.clientNonce).","commonSituations":"A buggy or non-compliant PostgreSQL server or proxy. An active MITM attempting to relay a different SCRAM session. Rare: data corruption on the wire truncating the nonce. This is extremely uncommon with real PostgreSQL servers.","solutions":["Verify there is no proxy or MITM between the client and PostgreSQL (check PgBouncer, load balancers, SSL termination).","If using SSL, ensure it is properly established so the SCRAM exchange is integrity-protected.","If connecting to a custom PostgreSQL-compatible server, verify its SCRAM implementation correctly echoes the client nonce."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (/server nonce does not start with client nonce/i.test(err.message)) {\n    console.error('Possible MITM or non-compliant server in SCRAM exchange. Verify SSL and network path.');\n  }\n  throw err;\n}","preventionTips":["Use SSL/TLS to protect the SCRAM exchange from tampering or injection.","Verify there is no non-compliant proxy between client and server.","Connect directly to PostgreSQL when debugging auth issues to isolate intermediaries."],"tags":["sasl","security","authentication","nonce","mitm"],"analyzedSha":"c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711","analyzedAt":"2026-08-03T18:47:28.334Z","schemaVersion":2}