Skip to content

Commit 6a6db37

Browse files
committed
fix(dev): trim trailing slash before server.fs.deny check (#20968)
1 parent f88a1c0 commit 6a6db37

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,12 @@ export function isFileLoadingAllowed(
274274

275275
if (!fs.strict) return true
276276

277-
if (config.fsDenyGlob(filePath)) return false
277+
// NOTE: `fs.readFile('/foo.png/')` tries to load `'/foo.png'`
278+
// so we should check the path without trailing slash
279+
const filePathWithoutTrailingSlash = filePath.endsWith('/')
280+
? filePath.slice(0, -1)
281+
: filePath
282+
if (config.fsDenyGlob(filePathWithoutTrailingSlash)) return false
278283

279284
if (config.safeModulePaths.has(filePath)) return true
280285

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ import {
1313
import type { Page } from 'playwright-chromium'
1414
import WebSocket from 'ws'
1515
import testJSON from '../safe.json'
16-
import { browser, isServe, page, viteServer, viteTestUrl } from '~utils'
16+
import {
17+
browser,
18+
isServe,
19+
isWindows,
20+
page,
21+
viteServer,
22+
viteTestUrl,
23+
} from '~utils'
1724

1825
const __dirname = path.dirname(fileURLToPath(import.meta.url))
1926

@@ -538,6 +545,23 @@ describe.runIf(isServe)('invalid request', () => {
538545
expect(response).toContain('HTTP/1.1 403 Forbidden')
539546
})
540547

548+
test('should deny request to denied file when a request ends with \\', async () => {
549+
const response = await sendRawRequest(viteTestUrl, '/src/.env\\')
550+
expect(response).toContain(
551+
isWindows ? 'HTTP/1.1 403 Forbidden' : 'HTTP/1.1 404 Not Found',
552+
)
553+
})
554+
555+
test('should deny request to denied file when a request ends with \\ with /@fs/', async () => {
556+
const response = await sendRawRequest(
557+
viteTestUrl,
558+
path.posix.join('/@fs/', root, 'root/src/.env') + '\\',
559+
)
560+
expect(response).toContain(
561+
isWindows ? 'HTTP/1.1 403 Forbidden' : 'HTTP/1.1 404 Not Found',
562+
)
563+
})
564+
541565
test('should deny request with /@fs/ to denied file when a request has /.', async () => {
542566
const response = await sendRawRequest(
543567
viteTestUrl,

0 commit comments

Comments
 (0)