From bf3c5a1f8a2351e783163b71d6d58bb5b84616bb Mon Sep 17 00:00:00 2001 From: RajeshKumar11 Date: Sat, 31 Jan 2026 10:17:40 +0530 Subject: [PATCH] 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: https://github.com/nodejs/node/issues/61582 --- lib/_http_common.js | 16 ++++++++---- .../parallel/test-http-invalidheaderfield2.js | 25 +++++++++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/_http_common.js b/lib/_http_common.js index 019b73a1ff225e..7d8d3f28861459 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -256,12 +256,18 @@ function checkIsHttpToken(val) { return true; } -const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; +// Per Fetch spec (https://fetch.spec.whatwg.org/#header-value), header values: +// - Must contain no 0x00 (NUL) or HTTP newline bytes (0x0a LF, 0x0d CR) +// - Must be byte sequences (0x00-0xff), not arbitrary unicode +// This regex matches forbidden characters: NUL, LF, CR, or anything above 0xff. +// eslint-disable-next-line no-control-regex +const headerCharRegex = /[\x00\x0a\x0d]|[^\x00-\xff]/; /** - * True if val contains an invalid field-vchar - * field-value = *( field-content / obs-fold ) - * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] - * field-vchar = VCHAR / obs-text + * True if val contains an invalid header value character. + * Per https://fetch.spec.whatwg.org/#header-value, a header value must: + * - Have no leading or trailing HTTP tab or space bytes + * - Contain no 0x00 (NUL) or HTTP newline bytes (0x0a LF, 0x0d CR) + * - Be a valid byte sequence (code points 0x00-0xff only) * @param {string} val * @returns {boolean} */ diff --git a/test/parallel/test-http-invalidheaderfield2.js b/test/parallel/test-http-invalidheaderfield2.js index 1b4e9e6edb01f3..0b53a9e2f459cb 100644 --- a/test/parallel/test-http-invalidheaderfield2.js +++ b/test/parallel/test-http-invalidheaderfield2.js @@ -60,11 +60,22 @@ const { _checkIsHttpToken, _checkInvalidHeaderChar } = require('_http_common'); // Good header field values +// Per Fetch spec, header values may contain any byte (0x00-0xff) except +// NUL (0x00), LF (0x0a), and CR (0x0d). [ 'foo bar', 'foo\tbar', '0123456789ABCdef', '!@#$%^&*()-_=+\\;\':"[]{}<>,./?|~`', + // CTL characters (except NUL, LF, CR) are valid per Fetch spec + '\x01\x02\x03\x04\x05\x06\x07\x08', // 0x01-0x08 + 'foo\x0bbar', // VT (0x0b) + 'foo\x0cbar', // FF (0x0c) + '\x0e\x0f\x10\x11\x12\x13\x14\x15', // 0x0e-0x15 + '\x16\x17\x18\x19\x1a\x1b\x1c\x1d', // 0x16-0x1d + '\x1e\x1f', // 0x1e-0x1f + '\x7FMe!', // DEL (0x7f) + '\x80\x81\xff', // obs-text (0x80-0xff) ].forEach(function(str) { assert.strictEqual( _checkInvalidHeaderChar(str), false, @@ -72,15 +83,13 @@ const { _checkIsHttpToken, _checkInvalidHeaderChar } = require('_http_common'); }); // Bad header field values +// Only NUL (0x00), LF (0x0a), CR (0x0d), and characters > 0xff are invalid [ - 'foo\rbar', - 'foo\nbar', - 'foo\r\nbar', - '中文呢', // unicode - '\x7FMe!', - 'Testing 123\x00', - 'foo\vbar', - 'Ding!\x07', + 'foo\rbar', // CR (0x0d) + 'foo\nbar', // LF (0x0a) + 'foo\r\nbar', // CRLF + '中文呢', // unicode > 0xff + 'Testing 123\x00', // NUL (0x00) ].forEach(function(str) { assert.strictEqual( _checkInvalidHeaderChar(str), true,