{"id":"31d50b6106be0643","repo":"mongodb/node-mongodb-native","slug":"server-record-does-not-share-hostname-with-parent","errorCode":null,"errorMessage":"Server record does not share hostname with parent URI","messagePattern":"Server record does not share hostname with parent URI","errorType":"exception","errorClass":"MongoAPIError","httpStatus":null,"severity":"error","filePath":"src/utils.ts","lineNumber":1186,"sourceCode":"  //   will not satisfy an addressDomain that endsWith '.fake-trusted.site'\n  const addressDomain = `.${normalizedAddress.replace(allCharacterBeforeFirstDot, '')}`;\n  let srvHostDomain = srvIsLessThanThreeParts\n    ? normalizedSrvHost\n    : `.${normalizedSrvHost.replace(allCharacterBeforeFirstDot, '')}`;\n\n  if (!srvHostDomain.startsWith('.')) {\n    srvHostDomain = '.' + srvHostDomain;\n  }\n  if (\n    srvIsLessThanThreeParts &&\n    normalizedAddress.split('.').length <= normalizedSrvHost.split('.').length\n  ) {\n    throw new MongoAPIError(\n      'Server record does not have at least one more domain level than parent URI'\n    );\n  }\n  if (!addressDomain.endsWith(srvHostDomain)) {\n    throw new MongoAPIError('Server record does not share hostname with parent URI');\n  }\n}\n\n/**\n * Perform a get request that returns status and body.\n * @internal\n */\nexport function get(\n  url: URL | string,\n  options: http.RequestOptions = {}\n): Promise<{ body: string; status: number | undefined }> {\n  return new Promise((resolve, reject) => {\n    /* eslint-disable prefer-const */\n    let timeoutId: NodeJS.Timeout;\n    const request = http\n      .get(url, options, response => {\n        response.setEncoding('utf8');\n        let body = '';","sourceCodeStart":1168,"sourceCodeEnd":1204,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/utils.ts#L1168-L1204","documentation":"Thrown by checkParentDomainMatch() when a resolved SRV/TXT host's domain does not end with the srvHost's domain. This is the primary hostname-is-a-subdomain guard that prevents a compromised DNS server from redirecting the MongoDB client to attacker-controlled hosts, and is part of the cross-driver SRV security contract. It surfaces as a MongoAPIError and is checked from srv_polling.ts (runtime SRV polling) and connection_string.ts (initial TXT lookup).","triggerScenarios":"An SRV record for cluster.example.com returns a target like host.otherdomain.com that is not a subdomain of example.com; a TXT lookup hostname does not match the parent domain. Triggered at connect time and on every SRV polling cycle.","commonSituations":"DNS/Atlas misconfiguration publishing out-of-domain SRV targets; CNAME flattening that strips the parent domain; split-horizon DNS returning different records internally; testing setups pointing SRV at localhost or a third-party host.","solutions":["Correct the SRV records so every target hostname ends with the srvHost domain (e.g. host.cluster.example.com under cluster.example.com).","If you intentionally host MongoDB outside the srvHost domain, stop using mongodb+srv:// and use a plain mongodb:// seedlist instead.","Verify with `dig SRV _mongodb._tcp.<srvHost>` that all returned targets are subdomains of the parent.","Check for CNAME flattening or DNS proxies that rewrite target hostnames."],"exampleFix":"// before (SRV record returns host.not-subdomain.com)\nconst uri = 'mongodb+srv://cluster.example.com/'; // => MongoAPIError\n\n// after (fix DNS so SRV returns node1.cluster.example.com) OR use seedlist:\nconst uri = 'mongodb://node1.example.com:27017,node2.example.com:27017/?replicaSet=cluster0';","handlingStrategy":"try-catch","validationCode":"function assertSrvTargetIsChild(target: string, srvHost: string): void {\n  const t = target.endsWith('.') ? target.slice(0, -1) : target;\n  const s = srvHost.endsWith('.') ? srvHost.slice(0, -1) : srvHost;\n  if (!t.endsWith('.' + s) && t !== s) {\n    throw new Error(`SRV target ${target} is not a subdomain of ${srvHost}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (err instanceof MongoAPIError && /does not share hostname with parent URI/.test(err.message)) {\n    // DNS misconfiguration; switch to a mongodb:// seedlist or fix SRV records\n    throw new Error('SRV hostname mismatch; verify DNS records or use a mongodb:// seedlist', { cause: err });\n  }\n  throw err;\n}","preventionTips":["Run `dig SRV _mongodb._tcp.<srvHost>` and confirm each target is a subdomain of the parent.","Watch for CNAME flattening or DNS proxies that strip the parent domain.","When hosting MongoDB outside the srvHost domain, use mongodb:// seedlist instead of mongodb+srv://."],"tags":["dns","srv","security","connection-string"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}