{"id":"CVE-2026-49456","aliases":["EUVD-2026-70655","GHSA-43fc-v873-qw85"],"status":"published","title":"Waku: Open Redirect via `unstable_redirect` Helper","description":"Waku is the minimal React framework. Prior to version 1.0.0-beta.1, the unstable_redirect() helper exported from waku/router/server (packages/waku/src/router/define-router.tsx:156–161) accepts an arbitrary string and reflects it unchanged into the HTTP Location response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (//evil.example/) bypass naive https?://-only allow-list filters that developers might add as ad-hoc mitigations. This issue has been patched in version 1.0.0-beta.1.","severity":{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00398,"percentile":0.34442,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-601"],"published":"2026-07-08T20:30:21Z","modified":"2026-10-28T02:31:11Z","fixes":[{"ecosystem":"npm","package":"waku","fixed_in":["1.0.0-beta.1"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"waku","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"1.0.0-beta.0"},{"fixed":"1.0.0-beta.1"}]}]},{"source":"osv","ecosystem":"npm","package":"waku","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.0.0-beta.1"}]}]}],"products":[{"vendor":"wakujs","product":"waku"}],"references":[{"url":"https://github.com/wakujs/waku/security/advisories/GHSA-43fc-v873-qw85","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/wakujs/waku/pull/2090","tags":["x_refsource_MISC","fix"]},{"url":"https://github.com/wakujs/waku/releases/tag/v1.0.0-beta.1","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-43fc-v873-qw85"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/49xxx/CVE-2026-49456.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-49456","tags":["advisory"]},{"url":"https://github.com/wakujs/waku","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-49456","title":"Waku: Open Redirect via `unstable_redirect` Helper","description":"Waku is the minimal React framework. Prior to version 1.0.0-beta.1, the unstable_redirect() helper exported from waku/router/server (packages/waku/src/router/define-router.tsx:156–161) accepts an arbitrary string and reflects it unchanged into the HTTP Location response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (//evil.example/) bypass naive https?://-only allow-list filters that developers might add as ad-hoc mitigations. This issue has been patched in version 1.0.0-beta.1.","status":"published","published":"2026-09-03T18:15:54.213Z","modified":"2026-09-03T18:29:02.239Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low","assessor":"cna"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T13:35:10.963527Z"}],"euvd":[{"id":"EUVD-2026-70655","description":"Waku is the minimal React framework. Prior to version 1.0.0-beta.1, the unstable_redirect() helper exported from waku/router/server (packages/waku/src/router/define-router.tsx:156–161) accepts an arbitrary string and reflects it unchanged into the HTTP Location response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (//evil.example/) bypass naive https?://-only allow-list filters that developers might add as ad-hoc mitigations. This issue has been patched in version 1.0.0-beta.1.","status":"published","published":"2026-09-03T18:15:54Z","modified":"2026-09-03T18:29:02Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low"}],"updated_at":"2026-11-02T18:01:13.160542Z"}],"ghsa":[{"id":"GHSA-43fc-v873-qw85","title":"Waku has an Open Redirect via `unstable_redirect` Helper","description":"## Summary\n\nThe `unstable_redirect()` helper exported from `waku/router/server` (`packages/waku/src/router/define-router.tsx:156–161`) accepts an arbitrary string and reflects it unchanged into the HTTP `Location` response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (`//evil.example/`) bypass naive `https?://`-only allow-list filters that developers might add as ad-hoc mitigations.\n\nDynamic PoC confirmed against **waku 1.0.0-beta.0** (commit `8e9f542`) in an isolated Docker environment. Two independent dynamic runs produced identical results.\n\n---\n\n## Root Cause\n\n`packages/waku/src/router/define-router.tsx:156–161`:\n\n```ts\nexport function unstable_redirect(\n  location: string, // only URL `pathname` is supported.\n  status: 303 | 307 | 308 = 307,\n): never {\n  throw createCustomError('Redirect', { status, location });\n}\n```\n\nThe JSDoc comment states \"only URL `pathname` is supported\", but this constraint is expressed as documentation only — the function performs **no validation**. The `location` value propagates via `createCustomError` (`custom-errors.ts:22–26`) into an error digest, is recovered by `getErrorInfo` in the request handler (`handler.ts:79–89`), and reflected directly into `headers.location` of the outgoing `Response` with no sanitization:\n\n```ts\nif (info?.location) {\n  headers.location = info.location;   // handler.ts:87 — unvalidated reflection\n}\nreturn new Response(body, { status, headers });\n```\n\n---\n\n## Trigger (one-line summary)\n\nAny developer-supplied user input passed to `unstable_redirect()` is reflected unchanged into the HTTP `Location` header, enabling navigation to an attacker-controlled domain.\n\n---\n\n## Affected Entry Surfaces\n\n- `unstable_redirect(location, status?)` — `waku/router/server` public export\n- Any page/route component that passes `searchParams`, `query`, or other user-\n  controlled strings to `unstable_redirect` (the standard post-login or callback\n  redirect pattern)\n- All waku adapters (Node.js, Cloudflare Workers, Vercel Edge, Deno) share the same\n  `handler.ts` reflection path; cross-runtime CRLF parity is unaudited (see note\n  below)\n\n---\n\n## Additional Defense-in-Depth Concern\n\nOn Node.js, CRLF injection via the `Location` header is rejected by `node:_http_outgoing.setHeader` (`ERR_INVALID_CHAR`). This defense is **platform-specific** and not present in the waku source. Cloudflare Workers, Deno Deploy, and other edge runtimes have not been verified to offer equivalent protection. A cross-runtime audit is recommended.\n\n---\n\n## Suggested Fix Outline\n\nValidate the `location` argument inside `unstable_redirect` before the error is thrown: reject any value that does not begin with a single `/` (no `//`), and reject any value containing control characters (`\\x00`–`\\x1f`). An opt-in allow-list for intentional cross-origin redirects can be provided via a framework configuration option.\n\n---\n\n## Disclosure\n\n| Field            | Value                              |\n|------------------|------------------------------------|\n| Reporter         | j0hndo (`dohyun4466@gmail.com`)    |\n| Discovery date   | 2026-05-17                         |\n| Embargo          | 90 days from acknowledgment        |\n| Patched version  | Not yet available                  |\n| Public references| CWE-601; OWASP A01:2021            |","status":"published","published":"2026-07-08T20:30:21Z","modified":"2026-07-08T20:30:23Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T14:40:41.501474Z"}],"nvd":[{"id":"CVE-2026-49456","description":"Waku is the minimal React framework. Prior to version 1.0.0-beta.1, the unstable_redirect() helper exported from waku/router/server (packages/waku/src/router/define-router.tsx:156–161) accepts an arbitrary string and reflects it unchanged into the HTTP Location response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (//evil.example/) bypass naive https?://-only allow-list filters that developers might add as ad-hoc mitigations. This issue has been patched in version 1.0.0-beta.1.","status":"published","published":"2026-09-03T19:17:28.25Z","modified":"2026-09-09T20:20:21.673Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low","assessor":"secondary"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T14:12:43.737972Z"}],"osv":[{"id":"CVE-2026-49456","title":"Waku: Open Redirect via `unstable_redirect` Helper","description":"Waku is the minimal React framework. Prior to version 1.0.0-beta.1, the unstable_redirect() helper exported from waku/router/server (packages/waku/src/router/define-router.tsx:156–161) accepts an arbitrary string and reflects it unchanged into the HTTP Location response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (//evil.example/) bypass naive https?://-only allow-list filters that developers might add as ad-hoc mitigations. This issue has been patched in version 1.0.0-beta.1.","status":"published","published":"2026-09-03T18:15:54.213Z","modified":"2026-10-28T02:31:11.228337109Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T15:45:07.060148Z"},{"id":"GHSA-43fc-v873-qw85","title":"Waku has an Open Redirect via `unstable_redirect` Helper","description":"## Summary\n\nThe `unstable_redirect()` helper exported from `waku/router/server` (`packages/waku/src/router/define-router.tsx:156–161`) accepts an arbitrary string and reflects it unchanged into the HTTP `Location` response header with no URL validation, scheme restriction, or path-only enforcement. Any application that passes user-controlled input to this helper — the natural pattern documented in the JSDoc and official fixtures — is vulnerable to open redirect attacks. An attacker who convinces a victim to click a crafted link can silently redirect the browser to an arbitrary external domain, enabling phishing, credential harvesting, and OAuth token theft. Additionally, scheme-relative URLs (`//evil.example/`) bypass naive `https?://`-only allow-list filters that developers might add as ad-hoc mitigations.\n\nDynamic PoC confirmed against **waku 1.0.0-beta.0** (commit `8e9f542`) in an isolated Docker environment. Two independent dynamic runs produced identical results.\n\n---\n\n## Root Cause\n\n`packages/waku/src/router/define-router.tsx:156–161`:\n\n```ts\nexport function unstable_redirect(\n  location: string, // only URL `pathname` is supported.\n  status: 303 | 307 | 308 = 307,\n): never {\n  throw createCustomError('Redirect', { status, location });\n}\n```\n\nThe JSDoc comment states \"only URL `pathname` is supported\", but this constraint is expressed as documentation only — the function performs **no validation**. The `location` value propagates via `createCustomError` (`custom-errors.ts:22–26`) into an error digest, is recovered by `getErrorInfo` in the request handler (`handler.ts:79–89`), and reflected directly into `headers.location` of the outgoing `Response` with no sanitization:\n\n```ts\nif (info?.location) {\n  headers.location = info.location;   // handler.ts:87 — unvalidated reflection\n}\nreturn new Response(body, { status, headers });\n```\n\n---\n\n## Trigger (one-line summary)\n\nAny developer-supplied user input passed to `unstable_redirect()` is reflected unchanged into the HTTP `Location` header, enabling navigation to an attacker-controlled domain.\n\n---\n\n## Affected Entry Surfaces\n\n- `unstable_redirect(location, status?)` — `waku/router/server` public export\n- Any page/route component that passes `searchParams`, `query`, or other user-\n  controlled strings to `unstable_redirect` (the standard post-login or callback\n  redirect pattern)\n- All waku adapters (Node.js, Cloudflare Workers, Vercel Edge, Deno) share the same\n  `handler.ts` reflection path; cross-runtime CRLF parity is unaudited (see note\n  below)\n\n---\n\n## Additional Defense-in-Depth Concern\n\nOn Node.js, CRLF injection via the `Location` header is rejected by `node:_http_outgoing.setHeader` (`ERR_INVALID_CHAR`). This defense is **platform-specific** and not present in the waku source. Cloudflare Workers, Deno Deploy, and other edge runtimes have not been verified to offer equivalent protection. A cross-runtime audit is recommended.\n\n---\n\n## Suggested Fix Outline\n\nValidate the `location` argument inside `unstable_redirect` before the error is thrown: reject any value that does not begin with a single `/` (no `//`), and reject any value containing control characters (`\\x00`–`\\x1f`). An opt-in allow-list for intentional cross-origin redirects can be provided via a framework configuration option.\n\n---\n\n## Disclosure\n\n| Field            | Value                              |\n|------------------|------------------------------------|\n| Reporter         | j0hndo (`dohyun4466@gmail.com`)    |\n| Discovery date   | 2026-05-17                         |\n| Embargo          | 90 days from acknowledgment        |\n| Patched version  | Not yet available                  |\n| Public references| CWE-601; OWASP A01:2021            |","status":"published","published":"2026-07-08T20:30:21Z","modified":"2026-07-08T20:56:35.817296Z","cvss":[{"version":"3.1","score":3.1,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N","level":"low"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T15:46:36.434231Z"}]}}
