## Summary 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. Dynamic PoC confirmed against **waku 1.0.0-beta.0** (commit `8e9f542`) in an isolated Docker environment. Two independent dynamic runs produced identical results. --- ## Root Cause `packages/waku/src/router/define-router.tsx:156–161`: ```ts export function unstable_redirect( location: string, // only URL `pathname` is supported. status: 303 | 307 | 308 = 307, ): never { throw createCustomError('Redirect', { status, location }); } ``` The 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: ```ts if (info?.location) { headers.location = info.location; // handler.ts:87 — unvalidated reflection } return new Response(body, { status, headers }); ``` --- ## Trigger (one-line summary) Any developer-supplied user input passed to `unstable_redirect()` is reflected unchanged into the HTTP `Location` header, enabling navigation to an attacker-controlled domain. --- ## Affected Entry Surfaces - `unstable_redirect(location, status?)` — `waku/router/server` public export - Any page/route component that passes `searchParams`, `query`, or other user- controlled strings to `unstable_redirect` (the standard post-login or callback redirect pattern) - All waku adapters (Node.js, Cloudflare Workers, Vercel Edge, Deno) share the same `handler.ts` reflection path; cross-runtime CRLF parity is unaudited (see note below) --- ## Additional Defense-in-Depth Concern On 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. --- ## Suggested Fix Outline Validate 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. --- ## Disclosure | Field | Value | |------------------|------------------------------------| | Reporter | j0hndo (`[email protected]`) | | Discovery date | 2026-05-17 | | Embargo | 90 days from acknowledgment | | Patched version | Not yet available | | Public references| CWE-601; OWASP A01:2021 |
## Summary 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. Dynamic PoC confirmed against **waku 1.0.0-beta.0** (commit `8e9f542`) in an isolated Docker environment. Two independent dynamic runs produced identical results. --- ## Root Cause `packages/waku/src/router/define-router.tsx:156–161`: ```ts export function unstable_redirect( location: string, // only URL `pathname` is supported. status: 303 | 307 | 308 = 307, ): never { throw createCustomError('Redirect', { status, location }); } ``` The 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: ```ts if (info?.location) { headers.location = info.location; // handler.ts:87 — unvalidated reflection } return new Response(body, { status, headers }); ``` --- ## Trigger (one-line summary) Any developer-supplied user input passed to `unstable_redirect()` is reflected unchanged into the HTTP `Location` header, enabling navigation to an attacker-controlled domain. --- ## Affected Entry Surfaces - `unstable_redirect(location, status?)` — `waku/router/server` public export - Any page/route component that passes `searchParams`, `query`, or other user- controlled strings to `unstable_redirect` (the standard post-login or callback redirect pattern) - All waku adapters (Node.js, Cloudflare Workers, Vercel Edge, Deno) share the same `handler.ts` reflection path; cross-runtime CRLF parity is unaudited (see note below) --- ## Additional Defense-in-Depth Concern On 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. --- ## Suggested Fix Outline Validate 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. --- ## Disclosure | Field | Value | |------------------|------------------------------------| | Reporter | j0hndo (`[email protected]`) | | Discovery date | 2026-05-17 | | Embargo | 90 days from acknowledgment | | Patched version | Not yet available | | Public references| CWE-601; OWASP A01:2021 |
Update waku to 1.0.0-beta.1 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanWaku has an Open Redirect via `unstable_redirect` Helper affects waku (npm). Severity is low. ## Summary 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. Dynamic PoC confirmed against **waku 1.0.0-beta.0** (commit `8e9f542`) in an isolated Docker environment. Two independent dynamic runs produced identical results. --- ## Root Cause `packages/waku/src/router/define-router.tsx:156–161`: ```ts export function unstable_redirect( location: string, // only URL `pathname` is supported. status: 303 | 307 | 308 = 307, ): never { throw createCustomError('Redirect', { status, location }); } ``` The 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: ```ts if (info?.location) { headers.location = info.location; // handler.ts:87 — unvalidated reflection } return new Response(body, { status, headers }); ``` --- ## Trigger (one-line summary) Any developer-supplied user input passed to `unstable_redirect()` is reflected unchanged into the HTTP `Location` header, enabling navigation to an attacker-controlled domain. --- ## Affected Entry Surfaces - `unstable_redirect(location, status?)` — `waku/router/server` public export - Any page/route component that passes `searchParams`, `query`, or other user- controlled strings to `unstable_redirect` (the standard post-login or callback redirect pattern) - All waku adapters (Node.js, Cloudflare Workers, Vercel Edge, Deno) share the same `handler.ts` reflection path; cross-runtime CRLF parity is unaudited (see note below) --- ## Additional Defense-in-Depth Concern On 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. --- ## Suggested Fix Outline Validate 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. --- ## Disclosure | Field | Value | |------------------|------------------------------------| | Reporter | j0hndo (`[email protected]`) | | Discovery date | 2026-05-17 | | Embargo | 90 days from acknowledgment | | Patched version | Not yet available | | Public references| CWE-601; OWASP A01:2021 |
AI coding agents often install or upgrade packages automatically in npm. A low vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| wakunpm | <=1.0.0-beta.0 | 1.0.0-beta.1 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL GuardUpdate waku to 1.0.0-beta.1 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanWaku has an Open Redirect via `unstable_redirect` Helper affects waku (npm). Severity is low. ## Summary 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. Dynamic PoC confirmed against **waku 1.0.0-beta.0** (commit `8e9f542`) in an isolated Docker environment. Two independent dynamic runs produced identical results. --- ## Root Cause `packages/waku/src/router/define-router.tsx:156–161`: ```ts export function unstable_redirect( location: string, // only URL `pathname` is supported. status: 303 | 307 | 308 = 307, ): never { throw createCustomError('Redirect', { status, location }); } ``` The 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: ```ts if (info?.location) { headers.location = info.location; // handler.ts:87 — unvalidated reflection } return new Response(body, { status, headers }); ``` --- ## Trigger (one-line summary) Any developer-supplied user input passed to `unstable_redirect()` is reflected unchanged into the HTTP `Location` header, enabling navigation to an attacker-controlled domain. --- ## Affected Entry Surfaces - `unstable_redirect(location, status?)` — `waku/router/server` public export - Any page/route component that passes `searchParams`, `query`, or other user- controlled strings to `unstable_redirect` (the standard post-login or callback redirect pattern) - All waku adapters (Node.js, Cloudflare Workers, Vercel Edge, Deno) share the same `handler.ts` reflection path; cross-runtime CRLF parity is unaudited (see note below) --- ## Additional Defense-in-Depth Concern On 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. --- ## Suggested Fix Outline Validate 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. --- ## Disclosure | Field | Value | |------------------|------------------------------------| | Reporter | j0hndo (`[email protected]`) | | Discovery date | 2026-05-17 | | Embargo | 90 days from acknowledgment | | Patched version | Not yet available | | Public references| CWE-601; OWASP A01:2021 |
AI coding agents often install or upgrade packages automatically in npm. A low vulnerability in a dependency can be pulled into a project through a normal install or update without a human reviewing the change, expanding the blast radius from a single package to every agent workspace that depends on it.
| Package | Affected range | Fixed version |
|---|---|---|
| wakunpm | <=1.0.0-beta.0 | 1.0.0-beta.1 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL Guard