mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #105] [MERGED] Security hardening: redirect sanitization, header stripping, ALS isolation tests, and safer command execution #315
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#315
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/105
Author: @threepointone
Created: 2/26/2026
Status: ✅ Merged
Merged: 2/26/2026
Merged by: @threepointone
Base:
main← Head:s-fixes📝 Commits (3)
d6d2c8dSanitize redirects/headers and use execFileSync996c3d9Rename middleware header to x-custom-middleware7002bc6Normalize leading slashes and strip headers📊 Changes
19 files changed (+385 additions, -60 deletions)
View changed files
📝
packages/vinext/src/cli.ts(+4 -4)📝
packages/vinext/src/config/config-matchers.ts(+32 -8)📝
packages/vinext/src/deploy.ts(+6 -4)📝
packages/vinext/src/index.ts(+6 -5)📝
packages/vinext/src/server/app-dev-server.ts(+13 -4)📝
packages/vinext/src/server/dev-server.ts(+13 -2)📝
packages/vinext/src/server/prod-server.ts(+5 -1)📝
packages/vinext/src/shims/fetch-cache.ts(+6 -0)📝
packages/vinext/src/shims/head.ts(+4 -1)📝
packages/vinext/src/shims/headers.ts(+4 -2)📝
tests/app-router.test.ts(+13 -5)📝
tests/e2e/app-router/headers-cookies.spec.ts(+5 -5)📝
tests/e2e/pages-router/middleware.spec.ts(+5 -5)📝
tests/fixtures/app-basic/middleware.ts(+6 -6)📝
tests/fixtures/pages-basic/middleware.ts(+1 -1)➕
tests/nextjs-compat/als-isolation.test.ts(+164 -0)📝
tests/nextjs-compat/draft-mode.test.ts(+37 -0)📝
tests/pages-router.test.ts(+7 -7)📝
tests/shims.test.ts(+54 -0)📄 Description
Summary
Comprehensive security hardening pass across the server, shims, and CLI layers. Fixes several classes of vulnerabilities and adds regression tests to prevent regressions.
Changes
Redirect & Rewrite Sanitization
config-matchers.ts—sanitizeDestination()now normalizes both leading slashes AND backslashes. Browsers interpret\as/in URL contexts, so\/evil.combecomes//evil.com(protocol-relative redirect). The regex^[\\/]+collapses any mix of leading slashes and backslashes to a single/.dev-server.ts— Apply the same backslash-aware sanitization toredirect.destinationfromgetServerSideProps/getStaticProps.index.ts— ApplysanitizeDestinationLocal()(same logic) to redirect paths in the Cloudflare Worker entry, ensuring dev/prod parity.External Rewrite Proxy Hardening (
config-matchers.ts)cookie,authorization,x-api-key, andproxy-authorizationfrom requests before forwarding to external rewrite destinations. Previously, all request headers (including session cookies and auth tokens) were forwarded verbatim to third-party hosts.x-middleware-*internal routing headers from proxied requests.AbortSignaltimeout on upstream fetch calls. Returns504 Gateway Timeouton abort.Internal
x-middleware-*Header StrippingThe
x-middleware-*prefix is reserved for internal routing signals (continue, rewrite, override-headers, invoke, request-* unpacking) and must never reach clients. This matches Next.js behavior.prod-server.ts— Strip allx-middleware-*headers from the response after unpackingx-middleware-request-*into the actual request.app-dev-server.ts— Same stripping applied to the App Router path, fixing a dev/prod parity gap where onlyx-middleware-request-*was previously removed.x-middleware-testtox-custom-middleware(Pages Router) andx-middleware-ran/x-middleware-pathnametox-mw-ran/x-mw-pathname(App Router) since the prefix is now correctly reserved..rscSuffix Stripped from Middleware NextRequest (app-dev-server.ts)The
.rscsuffix is an internal transport detail for RSC stream requests. Previously,NextRequest.nextUrl.pathnameinside middleware would be/about.rscinstead of/about, causing exact-match guards to silently fail. Now the URL is cleaned before constructing theNextRequest.Draft Mode Cookie Security (
headers.ts)Add
Secureflag to the__prerender_bypassdraft mode cookie whenNODE_ENV === "production". Prevents the cookie from being transmitted over unencrypted HTTP in production.Safer Command Execution (
deploy.ts,cli.ts)Convert all
execSync()calls with string interpolation toexecFileSync()with argument arrays. Defense-in-depth against future changes that might introduce user-controlled input.Security Documentation
head.ts— Document SSR/CSR divergence fordangerouslySetInnerHTMLand stored XSS risk.fetch-cache.ts— DocumentAUTH_HEADERSallowlist limitation (only 3 headers keyed; custom auth headers needcache: "no-store").Tests Added
ALS Per-Request Isolation (
tests/nextjs-compat/als-isolation.test.ts)Four concurrency regression tests verifying
AsyncLocalStorageproperly isolates per-request state:x-request-idOther Regression Tests
.rscsuffix stripping (tests/app-router.test.ts) — Asserts middleware sees/about, not/about.rsctests/nextjs-compat/draft-mode.test.ts) — Asserts cookie contains; Securein productiontests/shims.test.ts) — Assertscookie,authorization,x-api-key,proxy-authorization, andx-middleware-*are strippedtests/shims.test.ts) — Asserts\/evil.com,\\evil.com, etc. are all collapsed to/evil.comFiles Changed
config-matchers.tsserver/prod-server.tsx-middleware-*headers from client responsesserver/app-dev-server.ts.rscfrom middleware URL + stripx-middleware-*from responsesserver/dev-server.tsindex.tsshims/headers.tsSecureflag on draft mode cookie in productionshims/head.tsshims/fetch-cache.tsdeploy.tsexecSync→execFileSynccli.tsexecSync→execFileSynctests/nextjs-compat/als-isolation.test.tstests/app-router.test.ts.rscsuffix + header renametests/nextjs-compat/draft-mode.test.tstests/shims.test.tstests/e2e/pages-router/middleware.spec.tstests/e2e/app-router/headers-cookies.spec.tstests/fixtures/app-basic/middleware.tstests/fixtures/pages-basic/middleware.tstests/fixtures/pages-basic/dist/server/entry.js🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.