{"record":{"id":"9db1fd5f95821ac9","repo":"brianc/node-postgres","slug":"sasl-scram-server-first-message-nonce-must-only","errorCode":null,"errorMessage":"SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters","messagePattern":"SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":199,"sourceCode":"    text.split(',').map((attrValue) => {\n      if (!/^.=/.test(attrValue)) {\n        throw new Error('SASL: Invalid attribute pair entry')\n      }\n      const name = attrValue[0]\n      const value = attrValue.substring(2)\n      return [name, value]\n    })\n  )\n}\n\nfunction parseServerFirstMessage(data) {\n  const attrPairs = parseAttributePairs(data)\n\n  const nonce = attrPairs.get('r')\n  if (!nonce) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing')\n  } else if (!isPrintableChars(nonce)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters')\n  }\n  const salt = attrPairs.get('s')\n  if (!salt) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing')\n  } else if (!isBase64(salt)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt must be base64')\n  }\n  const iterationText = attrPairs.get('i')\n  if (!iterationText) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing')\n  } else if (!/^[1-9][0-9]*$/.test(iterationText)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: invalid iteration count')\n  }\n  const iteration = parseInt(iterationText, 10)\n\n  return {\n    nonce,\n    salt,","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/brianc/node-postgres/blob/ff9d775abd12f29dd6df03945253b54eabbb29f2/packages/pg/lib/crypto/sasl.js#L181-L217","documentation":"Thrown by parseServerFirstMessage() when the server's nonce contains characters outside the printable ASCII range defined by isPrintableChars() — specifically bytes 0x21-0x2B and 0x2D-0x7E (printable ASCII excluding comma). Per RFC 5802 the nonce must be printable. Non-printable characters could break the protocol's comma-delimited structure or indicate data corruption.","triggerScenarios":"At sasl.js:198-199, isPrintableChars(nonce) returns false. The nonce value extracted from the r= attribute contains at least one character with a char code outside 0x21-0x2B or 0x2D-0x7E — e.g., a control character (0x00-0x1F), DEL (0x7F), a comma (0x2C), or a high byte (0x80+).","commonSituations":"Data corruption in transit introducing binary/noise bytes into the nonce field; a buggy or malicious server injecting crafted nonce values; an encoding mismatch where raw binary data leaks into a text field; a proxy that re-encodes or mangles the authentication stream.","solutions":["Verify network integrity between client and server — check for corrupting proxies, firewalls, or VPNs.","Confirm the server is a legitimate PostgreSQL instance and not a spoofed/malicious endpoint.","Enable SSL/TLS to protect the authentication stream from in-transit corruption.","Test the connection with psql from the same host to isolate the issue."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect()\n} catch (err) {\n  if (err.message.includes('nonce must only contain printable characters')) {\n    throw new Error('Data corruption in SASL nonce — check network integrity and SSL configuration')\n  }\n  throw err\n}","preventionTips":["Enable SSL/TLS to protect the authentication stream from in-transit corruption.","Verify no proxy or firewall is altering authentication data.","Confirm the server is a legitimate PostgreSQL instance.","Test the connection from the same host using psql."],"tags":["authentication","sasl","scram","protocol-error","data-integrity","connection"],"backgroundTag":null,"analyzedSha":"ff9d775abd12f29dd6df03945253b54eabbb29f2","analyzedAt":"2026-08-11T15:33:59.644Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}