CVE-2022-21221: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)
value: The package github.com/valyala/fasthttp before 1.34.0 are vulnerable to Directory Traversal via the ServeFile function, due to improper sanitization. It is possible to be exploited by using a backslash %5c character in the path. **Note:** This security issue impacts Windows users only.
CWE description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
CVSS v3 base score: 7.5
Published: 2022-03-17T12:15Z
Repository: https://github.com/valyala/fasthttp
Language: Go
Files changed: fs.go, server.go
Commit date: 2022-03-03 08:51:13 +0100
Commit message: Warn about unsafe ServeFile usage (#1228)

See: https://github.com/valyala/fasthttp/issues/1226
Diff: diff --git a/fs.go b/fs.go
index 257f066..72c832a 100644
--- a/fs.go
+++ b/fs.go
@@ -28,10 +28,14 @@ import (
 //
 // ServeFileBytes may be used for saving network traffic when serving files
 // with good compression ratio.
 //
 // See also RequestCtx.SendFileBytes.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
 func ServeFileBytesUncompressed(ctx *RequestCtx, path []byte) {
 	ServeFileUncompressed(ctx, b2s(path))
 }
 
 // ServeFileUncompressed returns HTTP response containing file contents
@@ -41,10 +45,14 @@ func ServeFileBytesUncompressed(ctx *RequestCtx, path []byte) {
 //
 // ServeFile may be used for saving network traffic when serving files
 // with good compression ratio.
 //
 // See also RequestCtx.SendFile.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
 func ServeFileUncompressed(ctx *RequestCtx, path string) {
 	ctx.Request.Header.DelBytes(strAcceptEncoding)
 	ServeFile(ctx, path)
 }
 
@@ -60,10 +68,14 @@ func ServeFileUncompressed(ctx *RequestCtx, path string) {
 //
 // Use ServeFileBytesUncompressed is you don't need serving compressed
 // file contents.
 //
 // See also RequestCtx.SendFileBytes.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
 func ServeFileBytes(ctx *RequestCtx, path []byte) {
 	ServeFile(ctx, b2s(path))
 }
 
 // ServeFile returns HTTP response containing compressed file contents
@@ -77,10 +89,14 @@ func ServeFileBytes(ctx *RequestCtx, path []byte) {
 // Directory contents is returned if path points to directory.
 //
 // Use ServeFileUncompressed is you don't need serving compressed file contents.
 //
 // See also RequestCtx.SendFile.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
 func ServeFile(ctx *RequestCtx, path string) {
 	rootFSOnce.Do(func() {
 		rootFSHandler = rootFS.NewRequestHandler()
 	})
 	if len(path) == 0 || path[0] != '/' {
diff --git a/server.go b/server.go
index 82bc010..1a8ba8c 100644
--- a/server.go
+++ b/server.go
@@ -1336,10 +1336,14 @@ func (ctx *RequestCtx) ResetBody() {
 // This is a shortcut to ServeFile(ctx, path).
 //
 // SendFile logs all the errors via ctx.Logger.
 //
 // See also ServeFile, FSHandler and FS.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
 func (ctx *RequestCtx) SendFile(path string) {
 	ServeFile(ctx, path)
 }
 
 // SendFileBytes sends local file contents from the given path as response body.
@@ -1347,10 +1351,14 @@ func (ctx *RequestCtx) SendFile(path string) {
 // This is a shortcut to ServeFileBytes(ctx, path).
 //
 // SendFileBytes logs all the errors via ctx.Logger.
 //
 // See also ServeFileBytes, FSHandler and FS.
+//
+// WARNING: do not pass any user supplied paths to this function!
+// WARNING: if path is based on user input users will be able to request
+// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
 func (ctx *RequestCtx) SendFileBytes(path []byte) {
 	ServeFileBytes(ctx, path)
 }
 
 // IfModifiedSince returns true if lastModified exceeds 'If-Modified-Since'

Fixed code: //
// WARNING: do not pass any user supplied paths to this function!
// WARNING: if path is based on user input users will be able to request
// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
//
// WARNING: do not pass any user supplied paths to this function!
// WARNING: if path is based on user input users will be able to request
// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
//
// WARNING: do not pass any user supplied paths to this function!
// WARNING: if path is based on user input users will be able to request
// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
//
// WARNING: do not pass any user supplied paths to this function!
// WARNING: if path is based on user input users will be able to request
// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
//
// WARNING: do not pass any user supplied paths to this function!
// WARNING: if path is based on user input users will be able to request
// any file on your filesystem! Use fasthttp.FS with a sane Root instead.
//
// WARNING: do not pass any user supplied paths to this function!
// WARNING: if path is based on user input users will be able to request
// any file on your filesystem! Use fasthttp.FS with a sane Root instead.