Skip to content

Commit adb61c5

Browse files
authored
fix: backport #8979, re-encode url to prevent fs.allow bypass (fixes #8498) (#8990)
1 parent 84ec02a commit adb61c5

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

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

+12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ describe('main', () => {
4444
expect(await page.textContent('.unsafe-fetch-8498-status')).toBe('403')
4545
})
4646

47+
test('unsafe fetch with special characters 2 (#8498)', async () => {
48+
expect(await page.textContent('.unsafe-fetch-8498-2')).toMatch('')
49+
expect(await page.textContent('.unsafe-fetch-8498-2-status')).toBe('404')
50+
})
51+
4752
test('safe fs fetch', async () => {
4853
expect(await page.textContent('.safe-fs-fetch')).toBe(stringified)
4954
expect(await page.textContent('.safe-fs-fetch-status')).toBe('200')
@@ -66,6 +71,13 @@ describe('main', () => {
6671
expect(await page.textContent('.unsafe-fs-fetch-8498-status')).toBe('403')
6772
})
6873

74+
test('unsafe fs fetch with special characters 2 (#8498)', async () => {
75+
expect(await page.textContent('.unsafe-fs-fetch-8498-2')).toBe('')
76+
expect(await page.textContent('.unsafe-fs-fetch-8498-2-status')).toBe(
77+
'404'
78+
)
79+
})
80+
6981
test('nested entry', async () => {
7082
expect(await page.textContent('.nested-entry')).toBe('foobar')
7183
})

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

+29
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ <h2>Unsafe Fetch</h2>
1919
<pre class="unsafe-fetch"></pre>
2020
<pre class="unsafe-fetch-8498-status"></pre>
2121
<pre class="unsafe-fetch-8498"></pre>
22+
<pre class="unsafe-fetch-8498-2-status"></pre>
23+
<pre class="unsafe-fetch-8498-2"></pre>
2224

2325
<h2>Safe /@fs/ Fetch</h2>
2426
<pre class="safe-fs-fetch-status"></pre>
@@ -31,6 +33,8 @@ <h2>Unsafe /@fs/ Fetch</h2>
3133
<pre class="unsafe-fs-fetch"></pre>
3234
<pre class="unsafe-fs-fetch-8498-status"></pre>
3335
<pre class="unsafe-fs-fetch-8498"></pre>
36+
<pre class="unsafe-fs-fetch-8498-2-status"></pre>
37+
<pre class="unsafe-fs-fetch-8498-2"></pre>
3438

3539
<h2>Nested Entry</h2>
3640
<pre class="nested-entry"></pre>
@@ -100,6 +104,19 @@ <h2>Denied</h2>
100104
console.error(e)
101105
})
102106

107+
// outside of allowed dir with special characters 2 #8498
108+
fetch('/src/%252e%252e%252funsafe%252etxt')
109+
.then((r) => {
110+
text('.unsafe-fetch-8498-2-status', r.status)
111+
return r.text()
112+
})
113+
.then((data) => {
114+
text('.unsafe-fetch-8498-2', data)
115+
})
116+
.catch((e) => {
117+
console.error(e)
118+
})
119+
103120
// imported before, should be treated as safe
104121
fetch('/@fs/' + ROOT + '/safe.json')
105122
.then((r) => {
@@ -133,6 +150,18 @@ <h2>Denied</h2>
133150
text('.unsafe-fs-fetch-8498', JSON.stringify(data))
134151
})
135152

153+
// outside root with special characters 2 #8498
154+
fetch(
155+
'/@fs/' + ROOT + '/root/src/%252e%252e%252f%252e%252e%252funsafe%252ejson'
156+
)
157+
.then((r) => {
158+
text('.unsafe-fs-fetch-8498-2-status', r.status)
159+
return r.json()
160+
})
161+
.then((data) => {
162+
text('.unsafe-fs-fetch-8498-2', JSON.stringify(data))
163+
})
164+
136165
// not imported before, inside root with special characters, treated as safe
137166
fetch(
138167
'/@fs/' +

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export function serveStaticMiddleware(
107107
}
108108

109109
if (redirected) {
110-
req.url = redirected
110+
req.url = encodeURIComponent(redirected)
111111
}
112112

113113
serve(req, res, next)
@@ -142,7 +142,7 @@ export function serveRawFsMiddleware(
142142
url = url.slice(FS_PREFIX.length)
143143
if (isWindows) url = url.replace(/^[A-Z]:/i, '')
144144

145-
req.url = url
145+
req.url = encodeURIComponent(url)
146146
serveFromRoot(req, res, next)
147147
} else {
148148
next()

0 commit comments

Comments
 (0)