dev: the Host check on /__nuxt_dev__/* ignores vite.server.allowedHosts, so the error overlay is silently 403'd on hosts-file aliases
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 40/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- nodejs, typescript
Research direction
Start in the dev server's #syncAllowedHosts and isAllowedHost logic, plus #rejectDisallowedHost, to see how the host allow-set is built and why vite.server.allowedHosts is never read there. The overlay mount() fetch in the client is the other half: a non-OK response is silently dropped. Done means a Host listed in vite.server.allowedHosts gets a 200 on /__nuxt_dev__/progress, with the security trade-off for true settled first in the thread.
Written by the indexing model from the issue text.
Description
Environment
- @nuxt/cli 4.0.0 and 4.0.1 (same code path), nuxt 4.6.0 / 4.6.1, vite 8, node 24, macOS, Chrome 155
nuxt dev --https --host=0.0.0.0 --port=3000, app opened at a hosts-file alias (https://local.example.test:3000, 127.0.0.1)- nuxt.config:
vite: { server: { allowedHosts: true } }
What happens
- A client error is reported (
vue:error,app:error, windowerrororunhandledrejection->nuxt:dev:client-error). The server answers with the HMR eventnuxt:dev:errorcarrying/__nuxt_dev__/error-overlay/<id>. - The overlay plugin
fetch()es that URL withHost: local.example.test:3000. The CLI answers403 Forbidden: this host is not allowed. Pass it to--host, or--publicto allow any host.from#rejectDisallowedHost(host check, see #1484). mount()treats a non-OK response as 'no overlay' (res.ok ? res.text() : undefined) and.catch(() => {})s the rest, so nothing is logged. The developer sees a red 403 in the network tab and never sees the error. Onhttps://localhost:3000the overlay appears.
The same guard also rejects /__nuxt_dev__/error/{events,history,open}, /__nuxt_dev__/progress, and every path while the server is loading or a load failed (#serve), so an overlay injected into SSR HTML cannot subscribe to the channel either.
Why
#syncAllowedHosts only knows the --host value and listener.getURLs(), and isAllowedHost is an exact match on that set. vite.server.allowedHosts is never consulted, although the CLI already writes and merges it in #createListener. A project that declared its dev hostnames (or opted out of Vite's check with true) is still rejected by a second, independent allow-list. The only opt-out, --public, also sets devServer.cors = { origin: '*' }; --host=<alias> changes the bind interface and supports one name.
Proposal
- In
#syncAllowedHosts, also honornuxt.options.vite.server.allowedHosts:trueskips the check (the effect--publichas on the check, nothing else); an array is added to the allow-set, with Vite's leading-dot meaning (.example.com= domain + subdomains) inisAllowedHost. - Optional:
NUXT_DEV_ALLOWED_HOSTS(or a flag) so the list is also known before nuxt.config is loaded (the eager bind, the loading page and the load-failure page). - Overlay client:
console.warnwith the status when the overlay fetch is not OK, so a blocked overlay is not silent. - Longer term: split
--publicinto 'allow any Host' and 'CORS *', or document thatallowedHostsdoes not reach the CLI endpoints.
Security note: the check exists for DNS rebinding. The channel is created with allowedHosts: true (useErrorChannel), so the CLI check is the only rebinding defense for POST /__nuxt_dev__/error/open. An explicit list is therefore the conservative form, true should stay an explicit opt-in, and default behaviour stays unchanged.
Reproduction
- Any Nuxt 4.6 app with
vite: { server: { allowedHosts: true } }innuxt.config, started withnuxt dev --https --host=0.0.0.0 --port=3000(--https.cert/--https.keyfor a certificate that covers the alias). curl -sk -o /dev/null -w '%{http_code}\n' -H 'Host: local.example.test:3000' https://127.0.0.1:3000/__nuxt_dev__/progressreturns403, with the bodyForbidden: this host is not allowed. Pass it to `--host`, or `--public` to allow any host.- The same request with
-H 'Host: localhost:3000'returns200(the progress stream). - In a browser on a hosts-file alias (
127.0.0.1 local.example.test), trigger any client error. The network tab showsGET /__nuxt_dev__/error-overlay/<id>with 403, the console shows nothing, and no overlay appears. While the server is starting or restarting, document requests from the alias also get the plain-text 403 (no refresh), wherelocalhostgets the self-reloading loading screen.
Patch sketch (about 25 lines; applies to 4.0.0 and 4.0.1)
#syncAllowedHosts(options) {
const extra = resolveExtraAllowedHosts(this.#currentNuxt?.options.vite?.server?.allowedHosts, process.env.NUXT_DEV_ALLOWED_HOSTS);
this.#allowAnyHost = !!options.public || extra.any;
this.#allowedHosts.clear();
if (this.#allowAnyHost) return;
/* existing: --host value + listener URLs */
for (const host of extra.hosts) this.#allowedHosts.add(host);
}
isAllowedHost: after allowedHosts.has(hostname), also accept entries starting with . when hostname === entry.slice(1) || hostname.endsWith(entry).
Happy to send a PR if the direction is acceptable.
- Dominant language
- TypeScript
- Stars
- 401
- Forks
- 123
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 71
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from nuxt/cli
-
Difficulty 3/5 Half a day Newbie friendliness 45/100
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
Support pause HMRMay be free again A pull request for this issue was closed without being merged. Open
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
discussion
Difficulty 3/5 1-2 days Newbie friendliness 35/100
nuxt/cli#1166 · 7 comments · 2 reactions ·
Maintainers usually reply within 1 day
-
Feature request: Ability to overload and customise the templatesPossibly taken @oritwoen claimed this 65 days ago. Openenhancement good first issue
Difficulty 5/5 Over a week Newbie friendliness 35/100
nuxt/cli#1136 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
Similar issues
-
area:plugins enhancement platform:vscode
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
anthropics/claude-code#103166 ·
Maintainers usually reply within 1 day
-
check:failed streams:add
Difficulty 1/5 Under an hour Newbie friendliness 90/100
iptv-org/iptv#55744 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
jitsi/jitsi-meet#18021 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
Maintainers usually reply within 1 day
-
spec: discovery input example can contain multiple aliases for one parameter, with no canonical oneOpen
Difficulty 1/5 Under an hour Newbie friendliness 95/100
x402-foundation/x402#3841 ·
Maintainers usually reply within 1 day