From d3521e24f9b17f73a6bb99dc4041231b3f390c5a Mon Sep 17 00:00:00 2001 From: uzlopak Date: Tue, 27 Feb 2024 22:34:54 +0100 Subject: [PATCH] cookies: fix validateCookiePath --- lib/web/cookies/util.js | 11 ++++-- test/cookie/validate-cookie-path.js | 59 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 test/cookie/validate-cookie-path.js diff --git a/lib/web/cookies/util.js b/lib/web/cookies/util.js index 6d3a79b69ad..b3650e06a0a 100644 --- a/lib/web/cookies/util.js +++ b/lib/web/cookies/util.js @@ -90,10 +90,14 @@ function validateCookieValue (value) { * @param {string} path */ function validateCookiePath (path) { - for (const char of path) { - const code = char.charCodeAt(0) + for (let i = 0; i < path.length; ++i) { + const code = path.charCodeAt(i) - if (code < 0x21 || char === ';') { + if ( + code < 0x20 || // exclude CTLs (0-31) + code === 0x7F || // DEL + code === 0x3B // ; + ) { throw new Error('Invalid cookie path') } } @@ -287,6 +291,7 @@ function getHeadersList (headers) { module.exports = { isCTLExcludingHtab, + validateCookiePath, stringify, getHeadersList } diff --git a/test/cookie/validate-cookie-path.js b/test/cookie/validate-cookie-path.js new file mode 100644 index 00000000000..bcca0d2fc87 --- /dev/null +++ b/test/cookie/validate-cookie-path.js @@ -0,0 +1,59 @@ +'use strict' + +const { test, describe } = require('node:test') +const { throws, strictEqual } = require('node:assert') + +const { + validateCookiePath +} = require('../../lib/web/cookies/util') + +describe('validateCookiePath', () => { + test('should throw for CTLs', () => { + throws(() => validateCookiePath('\x00')) + throws(() => validateCookiePath('\x01')) + throws(() => validateCookiePath('\x02')) + throws(() => validateCookiePath('\x03')) + throws(() => validateCookiePath('\x04')) + throws(() => validateCookiePath('\x05')) + throws(() => validateCookiePath('\x06')) + throws(() => validateCookiePath('\x07')) + throws(() => validateCookiePath('\x08')) + throws(() => validateCookiePath('\x09')) + throws(() => validateCookiePath('\x0A')) + throws(() => validateCookiePath('\x0B')) + throws(() => validateCookiePath('\x0C')) + throws(() => validateCookiePath('\x0D')) + throws(() => validateCookiePath('\x0E')) + throws(() => validateCookiePath('\x0F')) + throws(() => validateCookiePath('\x10')) + throws(() => validateCookiePath('\x11')) + throws(() => validateCookiePath('\x12')) + throws(() => validateCookiePath('\x13')) + throws(() => validateCookiePath('\x14')) + throws(() => validateCookiePath('\x15')) + throws(() => validateCookiePath('\x16')) + throws(() => validateCookiePath('\x17')) + throws(() => validateCookiePath('\x18')) + throws(() => validateCookiePath('\x19')) + throws(() => validateCookiePath('\x1A')) + throws(() => validateCookiePath('\x1B')) + throws(() => validateCookiePath('\x1C')) + throws(() => validateCookiePath('\x1D')) + throws(() => validateCookiePath('\x1E')) + throws(() => validateCookiePath('\x1F')) + throws(() => validateCookiePath('\x7F')) + }) + + test('should throw for ; character', () => { + throws(() => validateCookiePath(';')) + }) + + test('should pass for a printable character', t => { + strictEqual(validateCookiePath('A'), undefined) + strictEqual(validateCookiePath('Z'), undefined) + strictEqual(validateCookiePath('a'), undefined) + strictEqual(validateCookiePath('z'), undefined) + strictEqual(validateCookiePath('!'), undefined) + strictEqual(validateCookiePath(' '), undefined) + }) +})