Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

dev: the Host check on /__nuxt_dev__/* ignores vite.server.allowedHosts, so the error overlay is silently 403'd on hosts-file aliases

オープン
#1,620 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
40/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
nodejs, typescript
領域
cli, security

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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
  1. A client error is reported (vue:error, app:error, window error or unhandledrejection -> nuxt:dev:client-error). The server answers with the HMR event nuxt:dev:error carrying /__nuxt_dev__/error-overlay/<id>.
  2. The overlay plugin fetch()es that URL with Host: local.example.test:3000. The CLI answers 403 Forbidden: this host is not allowed. Pass it to --host, or --public to allow any host. from #rejectDisallowedHost (host check, see #1484).
  3. 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. On https://localhost:3000 the 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
  1. In #syncAllowedHosts, also honor nuxt.options.vite.server.allowedHosts: true skips the check (the effect --public has on the check, nothing else); an array is added to the allow-set, with Vite's leading-dot meaning (.example.com = domain + subdomains) in isAllowedHost.
  2. 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).
  3. Overlay client: console.warn with the status when the overlay fetch is not OK, so a blocked overlay is not silent.
  4. Longer term: split --public into 'allow any Host' and 'CORS *', or document that allowedHosts does 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
  1. Any Nuxt 4.6 app with vite: { server: { allowedHosts: true } } in nuxt.config, started with nuxt dev --https --host=0.0.0.0 --port=3000 (--https.cert/--https.key for a certificate that covers the alias).
  2. curl -sk -o /dev/null -w '%{http_code}\n' -H 'Host: local.example.test:3000' https://127.0.0.1:3000/__nuxt_dev__/progress returns 403, with the body Forbidden: this host is not allowed. Pass it to `--host`, or `--public` to allow any host.
  3. The same request with -H 'Host: localhost:3000' returns 200 (the progress stream).
  4. In a browser on a hosts-file alias (127.0.0.1 local.example.test), trigger any client error. The network tab shows GET /__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), where localhost gets 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.

主要言語
TypeScript
スター
401
フォーク
123
平均マージ
1日 1時間
マージ済み PR(30日)
71

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

nuxt/cli のほかの issue

nuxt/cli の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。