From 72044b89941ada4a5e864d77257b4efb20aef498 Mon Sep 17 00:00:00 2001 From: "M.K" Date: Thu, 2 Apr 2020 01:18:03 +0200 Subject: [PATCH] v4.1.3: [security] Fix crash on redirect with formfeed in URL (CVE-2019-10775) (#266) * [minor] Remove else-after-return to make eslint pass * v4.1.3: [security] Fix crash on redirect with formfeed in URL (CVE-2019-10775) This fixes CVE-2019-10775. I'll postpone regression tests because the request library cannot send those requests (crashing the client instead of ecstatic), so I'll need to find another module that can. --- lib/ecstatic.js | 17 ++++++++++++++--- package.json | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/ecstatic.js b/lib/ecstatic.js index 6e415eb..64196ac 100644 --- a/lib/ecstatic.js +++ b/lib/ecstatic.js @@ -32,6 +32,13 @@ function decodePathname(pathname) { } +// eslint-disable-next-line no-control-regex +const nonUrlSafeCharsRgx = /[\x00-\x1F\x7F-\uFFFF]+/g; +function ensureUriEncoded(text) { + return String(text).replace(nonUrlSafeCharsRgx, encodeURIComponent); +} + + // Check to see if we should try to compress a file with gzip. function shouldCompressGzip(req) { const headers = req.headers; @@ -164,7 +171,8 @@ module.exports = function createMiddleware(_dir, _options) { if (opts.weakCompare && clientEtag !== serverEtag && clientEtag !== `W/${serverEtag}` && `W/${clientEtag}` !== serverEtag) { return false; - } else if (!opts.weakCompare && (clientEtag !== serverEtag || clientEtag.indexOf('W/') === 0)) { + } + if (!opts.weakCompare && (clientEtag !== serverEtag || clientEtag.indexOf('W/') === 0)) { return false; } } @@ -374,8 +382,10 @@ module.exports = function createMiddleware(_dir, _options) { }, res, next); } else { // Try to serve default ./404.html + const rawUrl = (handleError ? `/${path.join(baseDir, `404.${defaultExt}`)}` : req.url); + const encodedUrl = ensureUriEncoded(rawUrl); middleware({ - url: (handleError ? `/${path.join(baseDir, `404.${defaultExt}`)}` : req.url), + url: encodedUrl, headers: req.headers, statusCode: 404, }, res, next); @@ -393,7 +403,8 @@ module.exports = function createMiddleware(_dir, _options) { if (!pathname.match(/\/$/)) { res.statusCode = 302; const q = parsed.query ? `?${parsed.query}` : ''; - res.setHeader('location', `${parsed.pathname}/${q}`); + const d = `${parsed.pathname}/${q}`; + res.setHeader('location', ensureUriEncoded(d)); res.end(); return; } diff --git a/package.json b/package.json index 53dcf23..607da95 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Joshua Holbrook (http://jesusabdullah.net)", "name": "ecstatic", "description": "A simple static file server middleware", - "version": "4.1.2", + "version": "4.1.3", "homepage": "https://github.com/jfhbrook/node-ecstatic", "repository": { "type": "git",