1 Commits

Author SHA1 Message Date
Nathan Nguyen f335e2da3f fix(app-router): block javascript: URLs in router.push/replace/prefetch (#906)
* fix(app-router): block javascript: URLs in router.push/replace/prefetch

router.push("javascript:alert(1)") currently runs the script. _appRouter.push,
.replace, and .prefetch in shims/navigation.ts forward the href straight to
navigateClientSide, where isExternalUrl matches the javascript: scheme and
falls through to window.location.assign, which executes the URL. router-derived
hrefs (URL params, user content, query state) become an XSS vector.

Next.js blocks dangerous URI schemes at the router boundary and throws
"Next.js has blocked a javascript: URL as a security precaution." See
packages/next/src/client/components/app-router-instance.ts:343,400,440,458 in
the canary tree. Vinext's url-safety.isDangerousScheme already covers
javascript:/data:/vbscript: with the same obfuscation handling Next.js uses,
and Link and Form already gate on it; the App Router programmatic surface was
the remaining gap.

Add assertSafeNavigationHref at the top of push/replace/prefetch, before the
isServer short-circuit so SSR callers fail loudly too. Throw an Error with
the verbatim Next.js message so consumer error tooling can match across both
frameworks.

Test: tests/router-javascript-urls.test.ts ports the assertions from
.nextjs-ref/test/e2e/app-dir/javascript-urls/javascript-urls.test.ts down to
unit scope, covering javascript:/data:/vbscript:, uppercase, embedded tabs,
leading whitespace, and a safe-URL no-throw guard for each method.

* test(router): split ported vs vinext-only dangerous-scheme cases

The header said "Ported from Next.js" but data: and vbscript: are vinext
extensions, not in the upstream e2e suite. Add a Coverage split note that
attributes each scheme: javascript: + obfuscation variants come from
test/e2e/app-dir/javascript-urls/javascript-urls.test.ts; data: and vbscript:
ride on top via shims/url-safety.isDangerousScheme.

* fix app router dangerous redirect gaps

* test address dangerous URL review nits
2026-04-26 17:49:34 +01:00