Skip to content

Commit 64bfed9

Browse files
1 parent eefda2d commit 64bfed9

1 file changed

Lines changed: 135 additions & 0 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-hg3f-28rg-4jxj",
4+
"modified": "2026-05-29T17:15:11Z",
5+
"published": "2026-05-29T17:15:11Z",
6+
"aliases": [
7+
"CVE-2026-47200"
8+
],
9+
"summary": "Nuxt's route middleware is not enforced when rendering `.server.vue` pages via `/__nuxt_island/page_*`",
10+
"details": "### Summary\n\nWhen `experimental.componentIslands` is enabled (default in Nuxt 4), any `.server.vue` file under `pages/` is automatically registered as a server island under the key `page_<routeName>` and exposed via the `/__nuxt_island/:name` endpoint. Until this fix, requests through that endpoint rendered the page component directly via the SSR renderer without instantiating Vue Router, which meant route middleware declared on the page (including `definePageMeta({ middleware })`) did not run.\n\nFor Nuxt applications that gate a `.server.vue` *page* behind route middleware as their sole auth check, an unauthenticated attacker could bypass that check by requesting `/__nuxt_island/page_<routeName>_<anyhash>` directly and receiving the server-rendered HTML.\n\n### Affected configurations\n\nAll three conditions must hold for an application to be vulnerable:\n\n1. `experimental.componentIslands` is enabled (the default in Nuxt 4; opt-in in Nuxt 3).\n2. The application defines one or more `.server.vue` files under `pages/`, registering them as routed pages.\n3. Authentication / authorization for at least one such page is enforced solely via route middleware (`middleware/*.ts` referenced from `definePageMeta`), without a server-side check inside the page or its data layer.\n\nApplications that enforce auth inside the island's own data layer (server-only API routes, `useRequestEvent` + manual session checks, etc.) were not affected. The general \"route middleware does not run for non-page island *components*\" behaviour is documented and unchanged; this advisory concerns the `.server.vue` *page* case specifically, where running middleware is the user's clear expectation.\n\n### Details\n\n- Build (`packages/nuxt/src/components/templates.ts`): `.server.vue` pages are registered as island components with `page_` prefix, making them addressable through `/__nuxt_island/page_<routeName>_<hashId>`.\n- Runtime (`packages/nitro-server/src/runtime/handlers/island.ts`): the handler resolves the requested island component and renders it via `renderer.renderToString(ssrContext)`. The Vue Router plugin previously short-circuited middleware execution whenever `ssrContext.islandContext` was set.\n- The two paths interact so that route middleware declared on the source page never runs.\n\n### Proof of concept\n\nGiven a page `app/pages/secret.server.vue`:\n\n```vue\n<script setup lang=\"ts\">\ndefinePageMeta({ middleware: 'auth' })\n</script>\n\n<template>\n<h1>SECRET DATA</h1>\n</template>\n```\n\nwith `middleware/auth.ts` blocking unauthenticated access:\n\n```bash\n# Direct page request: blocked by middleware\ncurl -i http://localhost:3000/secret\n# -> 403 / redirect, depending on the middleware\n\n# Island request: middleware did not run before this fix\ncurl -i 'http://localhost:3000/__nuxt_island/page_secret_anyhash'\n# -> 200 OK, body includes <h1>SECRET DATA</h1>\n```\n\n### Patches\n\nPatched in `nuxt@4.4.6` and `nuxt@3.21.6` by [#35092](https://github.com/nuxt/nuxt/pull/35092). The Vue Router plugin now runs middleware and redirect handling for `page_*` islands (i.e. islands that originate from `.server.vue` files in `pages/`). The island handler propagates middleware-issued responses (`~renderResponse`), and a new `beforeResolve` guard returns HTTP 400 when the requested `page_<name>` does not match the route component the URL resolves to.\n\nNon-page island components are unaffected - they continue to render without route middleware, by design.\n\n### Workarounds\n\nIf you cannot upgrade immediately:\n\n- Enforce authentication inside the `.server.vue` page itself, not via route middleware. Read the session from `useRequestEvent()` and `throw createError({ statusCode: 401 })` (or redirect) before returning data. This is the recommended pattern for islands regardless of this advisory.\n- Disable `experimental.componentIslands` if your app does not use the feature.\n- If your app must keep route-middleware-only auth, gate the `/__nuxt_island/page_*` URL prefix at your reverse proxy or in a server middleware.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "nuxt"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "3.11.0"
29+
},
30+
{
31+
"fixed": "3.21.6"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 3.21.5"
38+
}
39+
},
40+
{
41+
"package": {
42+
"ecosystem": "npm",
43+
"name": "@nuxt/nitro-server"
44+
},
45+
"ranges": [
46+
{
47+
"type": "ECOSYSTEM",
48+
"events": [
49+
{
50+
"introduced": "3.20.0"
51+
},
52+
{
53+
"fixed": "3.21.6"
54+
}
55+
]
56+
}
57+
],
58+
"database_specific": {
59+
"last_known_affected_version_range": "<= 3.21.5"
60+
}
61+
},
62+
{
63+
"package": {
64+
"ecosystem": "npm",
65+
"name": "@nuxt/nitro-server"
66+
},
67+
"ranges": [
68+
{
69+
"type": "ECOSYSTEM",
70+
"events": [
71+
{
72+
"introduced": "4.2.0"
73+
},
74+
{
75+
"fixed": "4.4.6"
76+
}
77+
]
78+
}
79+
],
80+
"database_specific": {
81+
"last_known_affected_version_range": "<= 4.4.5"
82+
}
83+
},
84+
{
85+
"package": {
86+
"ecosystem": "npm",
87+
"name": "nuxt"
88+
},
89+
"ranges": [
90+
{
91+
"type": "ECOSYSTEM",
92+
"events": [
93+
{
94+
"introduced": "4.0.0-alpha.1"
95+
},
96+
{
97+
"fixed": "4.4.6"
98+
}
99+
]
100+
}
101+
],
102+
"database_specific": {
103+
"last_known_affected_version_range": "<= 4.4.5"
104+
}
105+
}
106+
],
107+
"references": [
108+
{
109+
"type": "WEB",
110+
"url": "https://github.com/nuxt/nuxt/security/advisories/GHSA-hg3f-28rg-4jxj"
111+
},
112+
{
113+
"type": "WEB",
114+
"url": "https://github.com/nuxt/nuxt/issues/19772"
115+
},
116+
{
117+
"type": "WEB",
118+
"url": "https://github.com/nuxt/nuxt/pull/35092"
119+
},
120+
{
121+
"type": "PACKAGE",
122+
"url": "https://github.com/nuxt/nuxt"
123+
}
124+
],
125+
"database_specific": {
126+
"cwe_ids": [
127+
"CWE-284",
128+
"CWE-288"
129+
],
130+
"severity": "MODERATE",
131+
"github_reviewed": true,
132+
"github_reviewed_at": "2026-05-29T17:15:11Z",
133+
"nvd_published_at": null
134+
}
135+
}

0 commit comments

Comments
 (0)