@@ -298,6 +298,27 @@ private function tryServeStaticFile(Request $request, Response $response): bool
298298 $ uri = substr ($ uri , 0 , $ pos );
299299 }
300300
301+ // Remove fragment
302+ if (($ pos = strpos ($ uri , '# ' )) !== false ) {
303+ $ uri = substr ($ uri , 0 , $ pos );
304+ }
305+
306+ // Decode URL-encoded characters to prevent encoded path traversal attacks
307+ $ uri = rawurldecode ($ uri );
308+
309+ // Security: Check for null bytes and reject
310+ if (strpos ($ uri , "\0" ) !== false ) {
311+ return false ;
312+ }
313+
314+ // Normalize path separators and remove consecutive slashes
315+ $ uri = preg_replace ('#/+# ' , '/ ' , $ uri );
316+
317+ // Security: Reject URIs containing path traversal patterns
318+ if (strpos ($ uri , '.. ' ) !== false ) {
319+ return false ;
320+ }
321+
301322 // Get file extension
302323 $ extension = pathinfo ($ uri , PATHINFO_EXTENSION );
303324
@@ -315,7 +336,13 @@ private function tryServeStaticFile(Request $request, Response $response): bool
315336 }
316337
317338 $ realPath = realpath ($ filePath );
318- if ($ realPath === false || strpos ($ realPath , $ this ->realDocRoot ) !== 0 ) {
339+ if ($ realPath === false ) {
340+ return false ;
341+ }
342+
343+ // Security: Ensure realPath is within documentRoot with proper directory boundary check
344+ $ realDocRootWithSeparator = rtrim ($ this ->realDocRoot , DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR ;
345+ if (strpos ($ realPath . DIRECTORY_SEPARATOR , $ realDocRootWithSeparator ) !== 0 ) {
319346 return false ;
320347 }
321348
@@ -333,6 +360,8 @@ private function tryServeStaticFile(Request $request, Response $response): bool
333360 // Set response headers
334361 $ response ->status (200 );
335362 $ response ->header ('Content-Type ' , $ this ->staticFileExtensions [$ extension ]);
363+ $ response ->header ('Content-Length ' , (string ) strlen ($ content ));
364+ $ response ->header ('X-Content-Type-Options ' , 'nosniff ' );
336365
337366 // Add cache headers for static files
338367 $ lastModified = filemtime ($ realPath );
0 commit comments