Skip to content

Commit 6851009

Browse files
authored
fix: /@fs/ dir traversal with escaped chars (fixes #8498) (#8804)
1 parent e53c029 commit 6851009

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

packages/vite/src/node/server/middlewares/static.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export function serveStaticMiddleware(
8080
return next()
8181
}
8282

83-
const url = decodeURI(req.url!)
83+
const url = decodeURIComponent(req.url!)
8484

8585
// apply aliases to static requests as well
8686
let redirected: string | undefined
@@ -123,7 +123,7 @@ export function serveRawFsMiddleware(
123123

124124
// Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...`
125125
return function viteServeRawFsMiddleware(req, res, next) {
126-
let url = decodeURI(req.url!)
126+
let url = decodeURIComponent(req.url!)
127127
// In some cases (e.g. linked monorepos) files outside of root will
128128
// reference assets that are also out of served root. In such cases
129129
// the paths are rewritten to `/@fs/` prefixed paths and must be served by

playground/fs-serve/__tests__/fs-serve.spec.ts

+12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ describe.runIf(isServe)('main', () => {
3535
expect(await page.textContent('.unsafe-fetch-status')).toBe('403')
3636
})
3737

38+
test('unsafe fetch with special characters (#8498)', async () => {
39+
expect(await page.textContent('.unsafe-fetch-8498')).toMatch(
40+
'403 Restricted'
41+
)
42+
expect(await page.textContent('.unsafe-fetch-8498-status')).toBe('403')
43+
})
44+
3845
test('safe fs fetch', async () => {
3946
expect(await page.textContent('.safe-fs-fetch')).toBe(stringified)
4047
expect(await page.textContent('.safe-fs-fetch-status')).toBe('200')
@@ -52,6 +59,11 @@ describe.runIf(isServe)('main', () => {
5259
expect(await page.textContent('.unsafe-fs-fetch-status')).toBe('403')
5360
})
5461

62+
test('unsafe fs fetch with special characters (#8498)', async () => {
63+
expect(await page.textContent('.unsafe-fs-fetch-8498')).toBe('')
64+
expect(await page.textContent('.unsafe-fs-fetch-8498-status')).toBe('403')
65+
})
66+
5567
test('nested entry', async () => {
5668
expect(await page.textContent('.nested-entry')).toBe('foobar')
5769
})

playground/fs-serve/root/src/index.html

+27
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ <h2>Safe Fetch Subdirectory</h2>
1717
<h2>Unsafe Fetch</h2>
1818
<pre class="unsafe-fetch-status"></pre>
1919
<pre class="unsafe-fetch"></pre>
20+
<pre class="unsafe-fetch-8498-status"></pre>
21+
<pre class="unsafe-fetch-8498"></pre>
2022

2123
<h2>Safe /@fs/ Fetch</h2>
2224
<pre class="safe-fs-fetch-status"></pre>
@@ -27,6 +29,8 @@ <h2>Safe /@fs/ Fetch</h2>
2729
<h2>Unsafe /@fs/ Fetch</h2>
2830
<pre class="unsafe-fs-fetch-status"></pre>
2931
<pre class="unsafe-fs-fetch"></pre>
32+
<pre class="unsafe-fs-fetch-8498-status"></pre>
33+
<pre class="unsafe-fs-fetch-8498"></pre>
3034

3135
<h2>Nested Entry</h2>
3236
<pre class="nested-entry"></pre>
@@ -83,6 +87,19 @@ <h2>Denied</h2>
8387
console.error(e)
8488
})
8589

90+
// outside of allowed dir with special characters #8498
91+
fetch('/src/%2e%2e%2funsafe%2etxt')
92+
.then((r) => {
93+
text('.unsafe-fetch-8498-status', r.status)
94+
return r.text()
95+
})
96+
.then((data) => {
97+
text('.unsafe-fetch-8498', data)
98+
})
99+
.catch((e) => {
100+
console.error(e)
101+
})
102+
86103
// imported before, should be treated as safe
87104
fetch('/@fs/' + ROOT + '/safe.json')
88105
.then((r) => {
@@ -106,6 +123,16 @@ <h2>Denied</h2>
106123
console.error(e)
107124
})
108125

126+
// outside root with special characters #8498
127+
fetch('/@fs/' + ROOT + '/root/src/%2e%2e%2f%2e%2e%2funsafe%2ejson')
128+
.then((r) => {
129+
text('.unsafe-fs-fetch-8498-status', r.status)
130+
return r.json()
131+
})
132+
.then((data) => {
133+
text('.unsafe-fs-fetch-8498', JSON.stringify(data))
134+
})
135+
109136
// not imported before, inside root with special characters, treated as safe
110137
fetch(
111138
'/@fs/' +

0 commit comments

Comments
 (0)