From 96f748c707308bf37fc5dece20e7a26ee143f227 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Thu, 19 Jun 2025 10:57:02 +0200 Subject: [PATCH 1/5] validate server action request --- packages/gitbook-v2/src/middleware.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index 4bcbf77aea..061e04a74b 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -43,6 +43,12 @@ export async function middleware(request: NextRequest) { return NextResponse.redirect(normalized.toString()); } + // Reject malicious requests + const rejectResponse = await validateServerActionRequest(request); + if (rejectResponse) { + return rejectResponse; + } + for (const handler of [serveSiteRoutes, serveSpacePDFRoutes]) { const result = await handler(requestURL, request); if (result) { @@ -56,6 +62,24 @@ export async function middleware(request: NextRequest) { } } +async function validateServerActionRequest(request: NextRequest) { + // We need to reject incorrect server actions requests + if (request.headers.has('next-action')) { + // We just test that the json body is parseable + try { + const clonedRequest = request.clone(); + await clonedRequest.json(); + } catch (e) { + console.warn('Invalid server action request', e); + // If the body is not parseable, we reject the request + return new Response('Invalid request', { + status: 400, + headers: { 'content-type': 'text/plain' }, + }); + } + } +} + /** * Handle request that are targetting the site routes group. */ From b882fe494ae1928a4567dd2f61e2aa4772887a55 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Thu, 19 Jun 2025 11:19:40 +0200 Subject: [PATCH 2/5] filter out site host that contains a port --- packages/gitbook-v2/src/middleware.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index 061e04a74b..7692f4867c 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -106,6 +106,14 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) { }); } + // We want to filter hostnames that contains a port here as this is likely a malicious request. + if (siteRequestURL.host.includes(':')) { + return new Response('Invalid request', { + status: 400, + headers: { 'content-type': 'text/plain' }, + }); + } + // // Detect and extract the visitor authentication token from the request // From 5918449eb8e59e3ec5c892fd23b2f9998405eb3c Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Thu, 19 Jun 2025 12:13:14 +0200 Subject: [PATCH 3/5] replace clone with new Request --- packages/gitbook-v2/src/middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index 7692f4867c..a88f187ec4 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -67,7 +67,7 @@ async function validateServerActionRequest(request: NextRequest) { if (request.headers.has('next-action')) { // We just test that the json body is parseable try { - const clonedRequest = request.clone(); + const clonedRequest = new Request(request.url, request); await clonedRequest.json(); } catch (e) { console.warn('Invalid server action request', e); From fc88c294a22676b3378356c513f4f06ed117b59f Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Thu, 19 Jun 2025 12:54:54 +0200 Subject: [PATCH 4/5] disable check for server actions on cloudflare --- packages/gitbook-v2/src/middleware.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index a88f187ec4..c0b527704a 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -64,10 +64,11 @@ export async function middleware(request: NextRequest) { async function validateServerActionRequest(request: NextRequest) { // We need to reject incorrect server actions requests - if (request.headers.has('next-action')) { + // We do not do it in cloudflare workers as there is a bug that prevents us from reading the request body. + if (request.headers.has('next-action') && !request.cf) { // We just test that the json body is parseable try { - const clonedRequest = new Request(request.url, request); + const clonedRequest = request.clone(); await clonedRequest.json(); } catch (e) { console.warn('Invalid server action request', e); From c4a941662d1eccfe2b5364c3a42a0027e6420a22 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Thu, 19 Jun 2025 13:12:11 +0200 Subject: [PATCH 5/5] use runtime env variable --- packages/gitbook-v2/src/middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index c0b527704a..b346d5a74d 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -65,7 +65,7 @@ export async function middleware(request: NextRequest) { async function validateServerActionRequest(request: NextRequest) { // We need to reject incorrect server actions requests // We do not do it in cloudflare workers as there is a bug that prevents us from reading the request body. - if (request.headers.has('next-action') && !request.cf) { + if (request.headers.has('next-action') && process.env.GITBOOK_RUNTIME !== 'cloudflare') { // We just test that the json body is parseable try { const clonedRequest = request.clone();