Skip to content

Commit 7788bf4

Browse files
committed
net: reject non-address SocketAddress.parse input
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
1 parent ede6d6a commit 7788bf4

3 files changed

Lines changed: 51 additions & 0 deletions

File tree

doc/api/net.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@ added:
295295
* Returns: {net.SocketAddress} Returns a `SocketAddress` if parsing was successful.
296296
Otherwise returns `undefined`.
297297

298+
The `input` may contain only hexadecimal digits, `x`, `.`, `:`, `[`, and `]`.
299+
Anything else returns `undefined`, including other URL components such as
300+
`user@1.2.3.4` or `1.2.3.4/foo`, whitespace, control characters,
301+
percent-encoding, and non-ASCII characters.
302+
298303
## Class: `net.Server`
299304

300305
<!-- YAML

lib/internal/socketaddress.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const {
44
ObjectSetPrototypeOf,
5+
RegExpPrototypeExec,
56
Symbol,
67
} = primordials;
78

@@ -42,6 +43,11 @@ const { URLParse } = require('internal/url');
4243
const kHandle = Symbol('kHandle');
4344
const kDetail = Symbol('kDetail');
4445

46+
// The complete character set of an "${address}:${port}" input. Everything else
47+
// is rejected: delimiters that would introduce a userinfo, path, query, or
48+
// fragment component, and characters the URL parser strips, decodes, or remaps.
49+
const kValidInput = /^[0-9a-fA-FxX.:[\]]+$/;
50+
4551
class SocketAddress {
4652
static isSocketAddress(value) {
4753
return value?.[kHandle] !== undefined;
@@ -149,6 +155,10 @@ class SocketAddress {
149155
*/
150156
static parse(input) {
151157
validateString(input, 'input');
158+
// The URL parser below silently discards anything that is not the host or
159+
// port, and percent-decodes and IDNA-maps what remains, so restrict the
160+
// input to characters that can appear in an address and port first.
161+
if (RegExpPrototypeExec(kValidInput, input) === null) return;
152162
// While URL.parse is not expected to throw, there are several
153163
// other pieces here that do... the destucturing, the SocketAddress
154164
// constructor, etc. So we wrap this in a try/catch to be safe.

test/parallel/test-socketaddress.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,42 @@ describe('net.SocketAddress...', () => {
162162
'abc.123',
163163
'259.1.1.1',
164164
'12:12:12',
165+
// Arbitrary URL components.
166+
'user:80@5.6.7.8',
167+
'user@1.2.3.4',
168+
'1.2.3.4/',
169+
'1.2.3.4/foo',
170+
'1.2.3.4\\foo',
171+
'1.2.3.4?a=b',
172+
'1.2.3.4#frag',
173+
'[1::8]:123/x',
174+
'http://1.2.3.4',
175+
// Whitespace and control characters.
176+
'1.2.3\n.4',
177+
'1.2.3\t.4',
178+
'1.2.3.4\r',
179+
'1.2.3.4 ',
180+
' 1.2.3.4',
181+
'1.2.3.4\x00',
182+
'1.2.3.4\x0b',
183+
'1.2.3.4\x7f',
184+
// Percent-encoding.
185+
'1.2.3.%34',
186+
'1%2E2%2E3%2E4',
187+
'%30%78%66%66%66%66%66%66%66%66',
188+
'1.2.3.%34:8080',
189+
// IDNA.
190+
'127.0.0.1',
191+
'0x7f.1',
192+
'1。2。3。4',
193+
'1。2。3。4',
194+
'⑧.0.0.1',
195+
'1.2.3.4\u200b',
196+
'1.2.3.4\ufeff',
197+
'1.2.3.4\u00ad',
198+
'1.2.3.4\u180e',
199+
'1.2.3.4\u2064',
200+
'1.2.3.4\ufe00',
165201
];
166202

167203
bad.forEach((i) => {

0 commit comments

Comments
 (0)