Skip to content

Commit bf3c5a1

Browse files
committed
http: align header value validation with Fetch spec
Per the Fetch spec, header values should only reject NUL (0x00), LF (0x0a), CR (0x0d), and characters above 0xff. Previously, Node.js rejected all CTL characters which was more restrictive than the spec and prevented valid use cases. This change relaxes the validation to match browser behavior while still protecting against response splitting attacks. Fixes: #61582
1 parent 784ca7b commit bf3c5a1

File tree

2 files changed

+28
-13
lines changed

2 files changed

+28
-13
lines changed

lib/_http_common.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,18 @@ function checkIsHttpToken(val) {
256256
return true;
257257
}
258258

259-
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
259+
// Per Fetch spec (https://fetch.spec.whatwg.org/#header-value), header values:
260+
// - Must contain no 0x00 (NUL) or HTTP newline bytes (0x0a LF, 0x0d CR)
261+
// - Must be byte sequences (0x00-0xff), not arbitrary unicode
262+
// This regex matches forbidden characters: NUL, LF, CR, or anything above 0xff.
263+
// eslint-disable-next-line no-control-regex
264+
const headerCharRegex = /[\x00\x0a\x0d]|[^\x00-\xff]/;
260265
/**
261-
* True if val contains an invalid field-vchar
262-
* field-value = *( field-content / obs-fold )
263-
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
264-
* field-vchar = VCHAR / obs-text
266+
* True if val contains an invalid header value character.
267+
* Per https://fetch.spec.whatwg.org/#header-value, a header value must:
268+
* - Have no leading or trailing HTTP tab or space bytes
269+
* - Contain no 0x00 (NUL) or HTTP newline bytes (0x0a LF, 0x0d CR)
270+
* - Be a valid byte sequence (code points 0x00-0xff only)
265271
* @param {string} val
266272
* @returns {boolean}
267273
*/

test/parallel/test-http-invalidheaderfield2.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,27 +60,36 @@ const { _checkIsHttpToken, _checkInvalidHeaderChar } = require('_http_common');
6060

6161

6262
// Good header field values
63+
// Per Fetch spec, header values may contain any byte (0x00-0xff) except
64+
// NUL (0x00), LF (0x0a), and CR (0x0d).
6365
[
6466
'foo bar',
6567
'foo\tbar',
6668
'0123456789ABCdef',
6769
'!@#$%^&*()-_=+\\;\':"[]{}<>,./?|~`',
70+
// CTL characters (except NUL, LF, CR) are valid per Fetch spec
71+
'\x01\x02\x03\x04\x05\x06\x07\x08', // 0x01-0x08
72+
'foo\x0bbar', // VT (0x0b)
73+
'foo\x0cbar', // FF (0x0c)
74+
'\x0e\x0f\x10\x11\x12\x13\x14\x15', // 0x0e-0x15
75+
'\x16\x17\x18\x19\x1a\x1b\x1c\x1d', // 0x16-0x1d
76+
'\x1e\x1f', // 0x1e-0x1f
77+
'\x7FMe!', // DEL (0x7f)
78+
'\x80\x81\xff', // obs-text (0x80-0xff)
6879
].forEach(function(str) {
6980
assert.strictEqual(
7081
_checkInvalidHeaderChar(str), false,
7182
`_checkInvalidHeaderChar(${inspect(str)}) unexpectedly failed`);
7283
});
7384

7485
// Bad header field values
86+
// Only NUL (0x00), LF (0x0a), CR (0x0d), and characters > 0xff are invalid
7587
[
76-
'foo\rbar',
77-
'foo\nbar',
78-
'foo\r\nbar',
79-
'中文呢', // unicode
80-
'\x7FMe!',
81-
'Testing 123\x00',
82-
'foo\vbar',
83-
'Ding!\x07',
88+
'foo\rbar', // CR (0x0d)
89+
'foo\nbar', // LF (0x0a)
90+
'foo\r\nbar', // CRLF
91+
'中文呢', // unicode > 0xff
92+
'Testing 123\x00', // NUL (0x00)
8493
].forEach(function(str) {
8594
assert.strictEqual(
8695
_checkInvalidHeaderChar(str), true,

0 commit comments

Comments
 (0)