From bb9f3f1ac78e15cc29a1a6c2f9d96d3ad31b7b39 Mon Sep 17 00:00:00 2001 From: Tobias Bocanegra Date: Wed, 18 Oct 2023 11:56:23 +0200 Subject: [PATCH] fix: reject dangerous url characters (--open) fixes #2257 --- src/abstract-server.cmd.js | 3 +++ test/abstract-server-cmd.test.js | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/abstract-server.cmd.js b/src/abstract-server.cmd.js index 23860891e..e2cebe1a7 100644 --- a/src/abstract-server.cmd.js +++ b/src/abstract-server.cmd.js @@ -137,6 +137,9 @@ export class AbstractServerCommand extends AbstractCommand { if (url.protocol !== 'http:' && url.protocol !== 'https:') { throw Error(`refuse to open non http(s) url (--open): ${url}`); } + if (!url.href.match(/^[a-zA-Z0-9._:/?%=&-]+$/)) { + throw Error(`refuse to open unsafe url (--open): ${url}`); + } this.log.info(`opening default browser: ${url.href}`); await opn(url.href); } diff --git a/test/abstract-server-cmd.test.js b/test/abstract-server-cmd.test.js index 8a73180fc..acd3aea59 100644 --- a/test/abstract-server-cmd.test.js +++ b/test/abstract-server-cmd.test.js @@ -30,6 +30,20 @@ describe('AbstractServerCommand test', () => { await assert.rejects(cmd.open('file://etc/passwd'), Error('refuse to open non http(s) url (--open): file://etc/passwd')); }); + it('open rejects invalid hostname argument', async () => { + const cmd = new AbstractServerCommand(); + // eslint-disable-next-line no-underscore-dangle + cmd._project = { server: { hostname: 'localhost', scheme: 'http', port: 3000 } }; + await assert.rejects(cmd.open('https://$(calc.exe)'), Error('refuse to open unsafe url (--open): https://$(calc.exe)/')); + }); + + it('open rejects invalid url argument', async () => { + const cmd = new AbstractServerCommand(); + // eslint-disable-next-line no-underscore-dangle + cmd._project = { server: { hostname: 'localhost', scheme: 'http', port: 3000 } }; + await assert.rejects(cmd.open('/"; Start calc.exe; echo "foo'), Error('refuse to open unsafe url (--open): http://localhost:3000/%22;%20Start%20calc.exe;%20echo%20%22foo')); + }); + it('constructs valid url from path', async () => { let opened; const { AbstractServerCommand: MockedCommand } = await esmock('../src/abstract-server.cmd.js', { @@ -40,7 +54,7 @@ describe('AbstractServerCommand test', () => { const cmd = new MockedCommand(); // eslint-disable-next-line no-underscore-dangle cmd._project = { server: { hostname: 'localhost', scheme: 'http', port: 3000 } }; - await cmd.open('/"; Start calc.exe; echo "foo'); - assert.strictEqual(opened, 'http://localhost:3000/%22;%20Start%20calc.exe;%20echo%20%22foo'); + await cmd.open('/test page'); + assert.strictEqual(opened, 'http://localhost:3000/test%20page'); }); });