@@ -13,11 +13,24 @@ type Options = {
1313
1414const ALLOWED_TXT_OPTIONS : Readonly < string [ ] > = [ 'authSource' , 'replicaSet' , 'loadBalanced' ] ;
1515
16- function matchesParentDomain ( srvAddress : string , parentDomain : string ) : boolean {
17- const regex = / ^ .* ?\. / ;
18- const srv = `.${ ( srvAddress . endsWith ( '.' ) ? srvAddress . slice ( 0 , - 1 ) : srvAddress ) . replace ( regex , '' ) } ` ;
19- const parent = `.${ ( parentDomain . endsWith ( '.' ) ? parentDomain . slice ( 0 , - 1 ) : parentDomain ) . replace ( regex , '' ) } ` ;
20- return srv . endsWith ( parent ) ;
16+ function matchesParentDomain ( address : string , parentDomain : string ) : void {
17+ const normalize = ( s : string ) : string => ( s . endsWith ( '.' ) ? s . slice ( 0 , - 1 ) : s ) ;
18+ const addr = normalize ( address ) ;
19+ const parent = normalize ( parentDomain ) ;
20+
21+ const addrParts = addr . split ( '.' ) ;
22+ const parentParts = parent . split ( '.' ) ;
23+ const isParentShort = parentParts . length < 3 ;
24+ if ( isParentShort && addrParts . length <= parentParts . length ) {
25+ throw new MongoParseError ( 'Server record does not have at least one more domain level than parent URI' ) ;
26+ }
27+
28+ // Prevent insecure "TLD-only matching" on short domains
29+ const requiredSuffix = `.${ parentParts . slice ( isParentShort ? 0 : 1 ) . join ( '.' ) } ` ;
30+ const addrSuffix = `.${ addrParts . slice ( 1 ) . join ( '.' ) } ` ;
31+ if ( ! addrSuffix . endsWith ( requiredSuffix ) ) {
32+ throw new MongoParseError ( 'Server record does not share hostname with parent URI' ) ;
33+ }
2134}
2235
2336async function resolveDnsSrvRecord ( dns : NonNullable < Options [ 'dns' ] > , lookupAddress : string , srvServiceName : string ) : Promise < string [ ] > {
@@ -27,9 +40,7 @@ async function resolveDnsSrvRecord (dns: NonNullable<Options['dns']>, lookupAddr
2740 }
2841
2942 for ( const { name } of addresses ) {
30- if ( ! matchesParentDomain ( name , lookupAddress ) ) {
31- throw new MongoParseError ( 'Server record does not share hostname with parent URI' ) ;
32- }
43+ matchesParentDomain ( name , lookupAddress ) ;
3344 }
3445
3546 return addresses . map ( r => r . name + ( ( r . port ?? 27017 ) === 27017 ? '' : `:${ r . port } ` ) ) ;
0 commit comments