Hacktoberfest 2026:维护者为十月标记出来的 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 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
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 小时
30 天内合并 PR
71

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

nuxt/cli 的其他 Issue

查看 nuxt/cli 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。