Skip to content

Commit bd1214a

Browse files
mcollinaaduh95
authored andcommitted
dns,net: reject hostnames with embedded NUL bytes
Refs: https://hackerone.com/reports/3656716 PR-URL: nodejs-private/node-private#868 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> CVE-ID: CVE-2026-48930
1 parent a14c158 commit bd1214a

6 files changed

Lines changed: 40 additions & 4 deletions

File tree

lib/dns.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const {
8383
validateNumber,
8484
validateOneOf,
8585
validatePort,
86-
validateString,
86+
validateStringWithoutNullBytes,
8787
} = require('internal/validators');
8888

8989
const {
@@ -147,7 +147,7 @@ function lookup(hostname, options, callback) {
147147

148148
// Parse arguments
149149
if (hostname) {
150-
validateString(hostname, 'hostname');
150+
validateStringWithoutNullBytes(hostname, 'hostname');
151151
}
152152

153153
if (typeof options === 'function') {

lib/internal/dns/promises.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const {
7070
validateOneOf,
7171
validatePort,
7272
validateString,
73+
validateStringWithoutNullBytes,
7374
} = require('internal/validators');
7475

7576
const kPerfHooksDnsLookupContext = Symbol('kPerfHooksDnsLookupContext');
@@ -200,7 +201,7 @@ function lookup(hostname, options) {
200201

201202
// Parse arguments
202203
if (hostname) {
203-
validateString(hostname, 'hostname');
204+
validateStringWithoutNullBytes(hostname, 'hostname');
204205
}
205206

206207
if (typeof options === 'number') {

lib/internal/validators.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
ObjectPrototypeHasOwnProperty,
1717
RegExpPrototypeExec,
1818
String,
19+
StringPrototypeIncludes,
1920
StringPrototypeToUpperCase,
2021
StringPrototypeTrim,
2122
} = primordials;
@@ -165,6 +166,14 @@ const validateString = hideStackFrames((value, name) => {
165166
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
166167
});
167168

169+
/** @type {validateString} */
170+
const validateStringWithoutNullBytes = hideStackFrames((value, name) => {
171+
validateString(value, name);
172+
if (StringPrototypeIncludes(value, '\u0000')) {
173+
throw new ERR_INVALID_ARG_VALUE(name, value, 'must be a string without null bytes');
174+
}
175+
});
176+
168177
/**
169178
* @callback validateNumber
170179
* @param {*} value
@@ -677,6 +686,7 @@ module.exports = {
677686
validatePort,
678687
validateSignalName,
679688
validateString,
689+
validateStringWithoutNullBytes,
680690
validateUint32,
681691
validateUndefined,
682692
validateUnion,

lib/net.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ const {
135135
validateNumber,
136136
validatePort,
137137
validateString,
138+
validateStringWithoutNullBytes,
138139
} = require('internal/validators');
139140
const kLastWriteQueueSize = Symbol('lastWriteQueueSize');
140141
const { getOptionValue } = require('internal/options');
@@ -1371,7 +1372,7 @@ function lookupAndConnect(self, options) {
13711372
const host = options.host || 'localhost';
13721373
let { port, autoSelectFamilyAttemptTimeout, autoSelectFamily } = options;
13731374

1374-
validateString(host, 'options.host');
1375+
validateStringWithoutNullBytes(host, 'options.host');
13751376

13761377
if (localAddress && !isIP(localAddress)) {
13771378
throw new ERR_INVALID_IP_ADDRESS(localAddress);

test/parallel/test-dns-lookup.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ const dnsPromises = dns.promises;
2323
assert.throws(() => dnsPromises.lookup(1, {}), err);
2424
}
2525

26+
{
27+
const err = {
28+
code: 'ERR_INVALID_ARG_VALUE',
29+
name: 'TypeError',
30+
message: /The argument 'hostname' must be a string without null bytes\./,
31+
};
32+
33+
assert.throws(() => dns.lookup('127.0.0.1\u0000.allowed.example', {}), err);
34+
assert.throws(() => dnsPromises.lookup('127.0.0.1\u0000.allowed.example', {}), err);
35+
}
36+
2637
// This also verifies different expectWarning notations.
2738
common.expectWarning({
2839
// For 'internal/test/binding' module.

test/parallel/test-net-connect-options-invalid.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,16 @@ const net = require('net');
3737
name: 'TypeError',
3838
});
3939
}
40+
41+
{
42+
assert.throws(() => {
43+
net.createConnection({
44+
host: '127.0.0.1\u0000.allowed.example',
45+
port: 8080,
46+
});
47+
}, {
48+
code: 'ERR_INVALID_ARG_VALUE',
49+
name: 'TypeError',
50+
message: /The property 'options\.host' must be a string without null bytes\./,
51+
});
52+
}

0 commit comments

Comments
 (0)