{"record":{"id":"1cfea67daf0769d6","repo":"mongodb/node-mongodb-native","slug":"server-returned-an-invalid-signature","errorCode":null,"errorMessage":"Server returned an invalid signature","messagePattern":"Server returned an invalid signature","errorType":"exception","errorClass":"MongoRuntimeError","httpStatus":null,"severity":"error","filePath":"src/cmap/auth/scram.ts","lineNumber":189,"sourceCode":"  const payloadString = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);\n  const authMessage = [firstMessage, payloadString, withoutProof].join(',');\n\n  const clientSignature = await HMAC(cryptoMethod, storedKey, authMessage);\n  const clientProof = `p=${xor(clientKey, clientSignature)}`;\n  const clientFinal = [withoutProof, clientProof].join(',');\n\n  const serverSignature = await HMAC(cryptoMethod, serverKey, authMessage);\n  const saslContinueCmd = {\n    saslContinue: 1,\n    conversationId: response.conversationId,\n    payload: new Binary(ByteUtils.fromUTF8(clientFinal))\n  };\n\n  const r = await connection.command(ns(`${db}.$cmd`), saslContinueCmd, undefined);\n  const parsedResponse = parsePayload(r.payload);\n\n  if (!compareDigest(ByteUtils.fromBase64(parsedResponse.v), serverSignature)) {\n    throw new MongoRuntimeError('Server returned an invalid signature');\n  }\n\n  if (r.done !== false) {\n    // If the server sends r.done === true we can save one RTT\n    return;\n  }\n\n  const retrySaslContinueCmd = {\n    saslContinue: 1,\n    conversationId: r.conversationId,\n    payload: ByteUtils.allocate(0)\n  };\n\n  await connection.command(ns(`${db}.$cmd`), retrySaslContinueCmd, undefined);\n}\n\nfunction parsePayload(payload: Binary) {\n  const payloadStr = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/cmap/auth/scram.ts#L171-L207","documentation":"Thrown by continueScramConversation (scram.ts:189) when the server's final SASL signature (parsedResponse.v) does not match the signature the client computed from its salted password. SCRAM uses this server signature to authenticate the server to the client; a mismatch means the party you are talking to does not hold the Server Key derived from your password. Raised as MongoRuntimeError.","triggerScenarios":"The client computed Server Key via HMAC and PBKDF2, then compared the server's returned 'v' value with a constant-time compareDigest; the two differed. This happens when the server is not the legitimate password-holding server, the exchange was tampered with, or (less commonly) the wire payload was corrupted.","commonSituations":"A man-in-the-middle intercepting the SCRAM exchange without knowing the password. A buggy proxy/gateway corrupting the final SASL payload. Connecting to a spoofed/misconfigured server. TLS disabled on an untrusted network allowing active tampering.","solutions":["Enable TLS/SSL on the connection (tls=true) to prevent tampering","Verify the hostname and server certificate against the deployment you expect","Remove proxies/load balancers that may alter the SASL payload","Confirm the cluster endpoint is the legitimate MongoDB deployment"],"exampleFix":"// before\nconst uri = 'mongodb://user:pass@cluster/?tls=false';\n\n// after\nconst uri = 'mongodb://user:pass@cluster/?tls=true&tlsCAFile=/etc/ssl/mongo-ca.pem';","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (err instanceof MongoRuntimeError && /invalid signature/.test(err.message)) {\n    // potential MITM or spoofed server; do not fall back to insecure transport\n    alertSecurityTeam(err);\n  }\n  throw err;\n}","preventionTips":["Always enable TLS (tls=true) and pin a trusted CA via tlsCAFile","Verify the server hostname/certificate matches your deployment","Remove TLS-terminating proxies that break end-to-end authentication integrity"],"tags":["scram","security","sasl","authentication","mitm"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}