diff --git a/src/index.js b/src/index.js index eb4dc6d..a245ca3 100644 --- a/src/index.js +++ b/src/index.js @@ -490,15 +490,26 @@ module.exports = async (request, response, config = {}, methods = {}) => { const cwd = process.cwd(); const current = config.public ? path.join(cwd, config.public) : cwd; const handlers = getHandlers(methods); - const relativePath = decodeURIComponent(url.parse(request.url).pathname); - let absolutePath = path.join(current, relativePath); + let relativePath = null; let acceptsJSON = null; if (request.headers.accept) { acceptsJSON = request.headers.accept.includes('application/json'); } + try { + relativePath = decodeURIComponent(url.parse(request.url).pathname); + } catch (err) { + return sendError(response, acceptsJSON, current, handlers, config, { + statusCode: 400, + code: 'bad_request', + message: 'Bad Request' + }); + } + + let absolutePath = path.join(current, relativePath); + // Prevent path traversal vulnerabilities. We could do this // by ourselves, but using the package covers all the edge cases. if (!isPathInside(absolutePath, current)) { diff --git a/test/integration.js b/test/integration.js index 1df2b3b..8b8ce61 100644 --- a/test/integration.js +++ b/test/integration.js @@ -956,3 +956,19 @@ test('allow dots in `public` configuration property', async t => { t.is(response.status, 200); t.is(content, text); }); + +test('error for request with malformed URI', async t => { + const url = await getUrl(); + const response = await fetch(`${url}/%E0%A4%A`); + const text = await response.text(); + + t.is(response.status, 400); + + const content = errorTemplate({ + statusCode: 400, + message: 'Bad Request' + }); + + t.is(text, content); +}); +