diff --git a/index.js b/index.js index b06d771..ae4365a 100644 --- a/index.js +++ b/index.js @@ -152,7 +152,11 @@ async function fastifyStatic (fastify, opts) { } if (opts.redirect === true) { - reply.redirect(301, getRedirectUrl(request.raw.url)) + try { + reply.redirect(301, getRedirectUrl(request.raw.url)) + } catch (error) { + reply.send(error) + } } else { reply.callNotFound() } @@ -443,8 +447,18 @@ function getEncodingExtension (encoding) { } function getRedirectUrl (url) { - const parsed = new URL(url, 'http://localhost.com/') - return parsed.pathname + (parsed.pathname[parsed.pathname.length - 1] !== '/' ? '/' : '') + (parsed.search || '') + if (url.startsWith('//') || url.startsWith('/\\')) { + // malicous redirect + return '/' + } + try { + const parsed = new URL(url, 'http://localhost.com/') + return parsed.pathname + (parsed.pathname[parsed.pathname.length - 1] !== '/' ? '/' : '') + (parsed.search || '') + } catch (error) { + const err = new Error(`Invalid redirect URL: ${url}`) + err.statusCode = 400 + throw err + } } module.exports = fp(fastifyStatic, { diff --git a/test/static.test.js b/test/static.test.js index dd1ba01..fdd59ac 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -3283,8 +3283,14 @@ t.test( } ) -t.test('should not redirect to protocol-relative locations', { only: 1 }, (t) => { +t.test('should not redirect to protocol-relative locations', (t) => { const urls = [ + ['//^/..', '/', 301], + ['//^/.', null, 404], // it is NOT recognized as a directory by pillarjs/send + ['//:/..', '/', 301], + ['/\\\\a//google.com/%2e%2e%2f%2e%2e', '/', 301], + ['//a//youtube.com/%2e%2e%2f%2e%2e', '/', 301], + ['/^', null, 404], // it is NOT recognized as a directory by pillarjs/send ['//google.com/%2e%2e', '/', 301], ['//users/%2e%2e', '/', 301], ['//users', null, 404]