@@ -43,6 +43,12 @@ export async function middleware(request: NextRequest) {
4343 return NextResponse . redirect ( normalized . toString ( ) ) ;
4444 }
4545
46+ // Reject malicious requests
47+ const rejectResponse = await validateServerActionRequest ( request ) ;
48+ if ( rejectResponse ) {
49+ return rejectResponse ;
50+ }
51+
4652 for ( const handler of [ serveSiteRoutes , serveSpacePDFRoutes ] ) {
4753 const result = await handler ( requestURL , request ) ;
4854 if ( result ) {
@@ -56,6 +62,25 @@ export async function middleware(request: NextRequest) {
5662 }
5763}
5864
65+ async function validateServerActionRequest ( request : NextRequest ) {
66+ // We need to reject incorrect server actions requests
67+ // We do not do it in cloudflare workers as there is a bug that prevents us from reading the request body.
68+ if ( request . headers . has ( 'next-action' ) && process . env . GITBOOK_RUNTIME !== 'cloudflare' ) {
69+ // We just test that the json body is parseable
70+ try {
71+ const clonedRequest = request . clone ( ) ;
72+ await clonedRequest . json ( ) ;
73+ } catch ( e ) {
74+ console . warn ( 'Invalid server action request' , e ) ;
75+ // If the body is not parseable, we reject the request
76+ return new Response ( 'Invalid request' , {
77+ status : 400 ,
78+ headers : { 'content-type' : 'text/plain' } ,
79+ } ) ;
80+ }
81+ }
82+ }
83+
5984/**
6085 * Handle request that are targetting the site routes group.
6186 */
@@ -82,6 +107,14 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
82107 } ) ;
83108 }
84109
110+ // We want to filter hostnames that contains a port here as this is likely a malicious request.
111+ if ( siteRequestURL . host . includes ( ':' ) ) {
112+ return new Response ( 'Invalid request' , {
113+ status : 400 ,
114+ headers : { 'content-type' : 'text/plain' } ,
115+ } ) ;
116+ }
117+
85118 //
86119 // Detect and extract the visitor authentication token from the request
87120 //
0 commit comments