From 6851009e6725b17608113a5a63474280075cae1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Mon, 27 Jun 2022 13:59:04 +0900 Subject: [PATCH] fix: /@fs/ dir traversal with escaped chars (fixes #8498) (#8804) --- .../src/node/server/middlewares/static.ts | 4 +-- .../fs-serve/__tests__/fs-serve.spec.ts | 12 +++++++++ playground/fs-serve/root/src/index.html | 27 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/server/middlewares/static.ts b/packages/vite/src/node/server/middlewares/static.ts index b5eb087b7b467c..9f18b6391face0 100644 --- a/packages/vite/src/node/server/middlewares/static.ts +++ b/packages/vite/src/node/server/middlewares/static.ts @@ -80,7 +80,7 @@ export function serveStaticMiddleware( return next() } - const url = decodeURI(req.url!) + const url = decodeURIComponent(req.url!) // apply aliases to static requests as well let redirected: string | undefined @@ -123,7 +123,7 @@ export function serveRawFsMiddleware( // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteServeRawFsMiddleware(req, res, next) { - let url = decodeURI(req.url!) + let url = decodeURIComponent(req.url!) // In some cases (e.g. linked monorepos) files outside of root will // reference assets that are also out of served root. In such cases // the paths are rewritten to `/@fs/` prefixed paths and must be served by diff --git a/playground/fs-serve/__tests__/fs-serve.spec.ts b/playground/fs-serve/__tests__/fs-serve.spec.ts index 747b46ecbb8287..2111cac80cc4e7 100644 --- a/playground/fs-serve/__tests__/fs-serve.spec.ts +++ b/playground/fs-serve/__tests__/fs-serve.spec.ts @@ -35,6 +35,13 @@ describe.runIf(isServe)('main', () => { expect(await page.textContent('.unsafe-fetch-status')).toBe('403') }) + test('unsafe fetch with special characters (#8498)', async () => { + expect(await page.textContent('.unsafe-fetch-8498')).toMatch( + '403 Restricted' + ) + expect(await page.textContent('.unsafe-fetch-8498-status')).toBe('403') + }) + test('safe fs fetch', async () => { expect(await page.textContent('.safe-fs-fetch')).toBe(stringified) expect(await page.textContent('.safe-fs-fetch-status')).toBe('200') @@ -52,6 +59,11 @@ describe.runIf(isServe)('main', () => { expect(await page.textContent('.unsafe-fs-fetch-status')).toBe('403') }) + test('unsafe fs fetch with special characters (#8498)', async () => { + expect(await page.textContent('.unsafe-fs-fetch-8498')).toBe('') + expect(await page.textContent('.unsafe-fs-fetch-8498-status')).toBe('403') + }) + test('nested entry', async () => { expect(await page.textContent('.nested-entry')).toBe('foobar') }) diff --git a/playground/fs-serve/root/src/index.html b/playground/fs-serve/root/src/index.html index 951e14ad2cce91..6939e0f4b09ed9 100644 --- a/playground/fs-serve/root/src/index.html +++ b/playground/fs-serve/root/src/index.html @@ -17,6 +17,8 @@

Safe Fetch Subdirectory

Unsafe Fetch


 

+

+

 
 

Safe /@fs/ Fetch


@@ -27,6 +29,8 @@ 

Safe /@fs/ Fetch

Unsafe /@fs/ Fetch


 

+

+

 
 

Nested Entry


@@ -83,6 +87,19 @@ 

Denied

console.error(e) }) + // outside of allowed dir with special characters #8498 + fetch('/src/%2e%2e%2funsafe%2etxt') + .then((r) => { + text('.unsafe-fetch-8498-status', r.status) + return r.text() + }) + .then((data) => { + text('.unsafe-fetch-8498', data) + }) + .catch((e) => { + console.error(e) + }) + // imported before, should be treated as safe fetch('/@fs/' + ROOT + '/safe.json') .then((r) => { @@ -106,6 +123,16 @@

Denied

console.error(e) }) + // outside root with special characters #8498 + fetch('/@fs/' + ROOT + '/root/src/%2e%2e%2f%2e%2e%2funsafe%2ejson') + .then((r) => { + text('.unsafe-fs-fetch-8498-status', r.status) + return r.json() + }) + .then((data) => { + text('.unsafe-fs-fetch-8498', JSON.stringify(data)) + }) + // not imported before, inside root with special characters, treated as safe fetch( '/@fs/' +