Skip to content

Commit 7d1699c

Browse files
committed
fix: allow CORS from loopback addresses by default (#19249)
1 parent 9df6e6b commit 7d1699c

File tree

5 files changed

+62
-7
lines changed

5 files changed

+62
-7
lines changed

docs/config/server-options.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export default defineConfig({
151151
## server.cors
152152

153153
- **Type:** `boolean | CorsOptions`
154-
- **Default:** `false`
154+
- **Default:** `{ origin: /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/ }` (allows localhost, `127.0.0.1` and `::1`)
155155

156156
Configure CORS for the dev server. Pass an [options object](https://github.com/expressjs/cors#configuration-options) to fine tune the behavior or `true` to allow any origin.
157157

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { expect, test } from 'vitest'
2+
import { defaultAllowedOrigins } from '../constants'
3+
4+
test('defaultAllowedOrigins', () => {
5+
const allowed = [
6+
'http://localhost',
7+
'http://foo.localhost',
8+
'http://localhost:3000',
9+
'https://localhost:3000',
10+
'http://127.0.0.1',
11+
'http://[::1]',
12+
'http://[::1]:3000',
13+
]
14+
const denied = [
15+
'file:///foo',
16+
'http://localhost.example.com',
17+
'http://foo.example.com:localhost',
18+
'http://',
19+
'http://192.0.2',
20+
'http://[2001:db8::1]',
21+
'http://vite',
22+
'http://vite:3000',
23+
]
24+
25+
for (const origin of allowed) {
26+
expect(defaultAllowedOrigins.test(origin), origin).toBe(true)
27+
}
28+
29+
for (const origin of denied) {
30+
expect(defaultAllowedOrigins.test(origin), origin).toBe(false)
31+
}
32+
})

packages/vite/src/node/constants.ts

+7
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,11 @@ export const DEFAULT_PREVIEW_PORT = 4173
141141

142142
export const DEFAULT_ASSETS_INLINE_LIMIT = 4096
143143

144+
// the regex to allow loopback address origins:
145+
// - localhost domains (which will always resolve to the loopback address by RFC 6761 section 6.3)
146+
// - 127.0.0.1
147+
// - ::1
148+
export const defaultAllowedOrigins =
149+
/^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/
150+
144151
export const METADATA_FILENAME = '_metadata.json'

packages/vite/src/node/preview.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import compression from '@polka/compression'
55
import connect from 'connect'
66
import type { Connect } from 'dep-types/connect'
77
import corsMiddleware from 'cors'
8-
import { DEFAULT_PREVIEW_PORT } from './constants'
8+
import { DEFAULT_PREVIEW_PORT, defaultAllowedOrigins } from './constants'
99
import type {
1010
HttpServer,
1111
ResolvedServerOptions,
@@ -186,8 +186,14 @@ export async function preview(
186186

187187
// cors
188188
const { cors } = config.preview
189-
if (cors !== undefined && cors !== false) {
190-
app.use(corsMiddleware(typeof cors === 'boolean' ? {} : cors))
189+
if (cors !== false) {
190+
app.use(
191+
corsMiddleware(
192+
typeof cors === 'boolean'
193+
? {}
194+
: (cors ?? { origin: defaultAllowedOrigins }),
195+
),
196+
)
191197
}
192198

193199
// host check (to prevent DNS rebinding attacks)

packages/vite/src/node/server/index.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ import { ERR_OUTDATED_OPTIMIZED_DEP } from '../plugins/optimizedDeps'
4646
import { getDepsOptimizer, initDepsOptimizer } from '../optimizer'
4747
import { bindCLIShortcuts } from '../shortcuts'
4848
import type { BindCLIShortcutsOptions } from '../shortcuts'
49-
import { CLIENT_DIR, DEFAULT_DEV_PORT } from '../constants'
49+
import {
50+
CLIENT_DIR,
51+
DEFAULT_DEV_PORT,
52+
defaultAllowedOrigins,
53+
} from '../constants'
5054
import type { Logger } from '../logger'
5155
import { printServerUrls } from '../logger'
5256
import {
@@ -850,8 +854,14 @@ export async function _createServer(
850854

851855
// cors
852856
const { cors } = serverConfig
853-
if (cors !== undefined && cors !== false) {
854-
middlewares.use(corsMiddleware(typeof cors === 'boolean' ? {} : cors))
857+
if (cors !== false) {
858+
middlewares.use(
859+
corsMiddleware(
860+
typeof cors === 'boolean'
861+
? {}
862+
: (cors ?? { origin: defaultAllowedOrigins }),
863+
),
864+
)
855865
}
856866

857867
// host check (to prevent DNS rebinding attacks)

0 commit comments

Comments
 (0)