CVE-2022-21221 (Go, published 2022-03-17T12:15Z)
Description: 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.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
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.
Repository: https://github.com/valyala/fasthttp
Files changed:
strings.go
uri.go
Commit message: Add windows support to normalizePath

This is probably still not 100% sure and there are still many bugs with
FS on windows. But it's a slight improvement.

Fixes #1226


Vulnerable code:
	strSlash            = []byte("/")
	strSlashSlash       = []byte("//")
	strSlashDotDot      = []byte("/..")
	strSlashDotSlash    = []byte("/./")
	strSlashDotDotSlash = []byte("/../")
	strCRLF             = []byte("\r\n")
	strHTTP             = []byte("http")
	strHTTPS            = []byte("https")
	strHTTP10           = []byte("HTTP/1.0")
	strHTTP11           = []byte("HTTP/1.1")
	strColon            = []byte(":")
	strColonSlashSlash  = []byte("://")
	strColonSpace       = []byte(": ")
	strCommaSpace       = []byte(", ")
	strGMT              = []byte("GMT")

Fixed code:
	strSlash                    = []byte("/")
	strSlashSlash               = []byte("//")
	strSlashDotDot              = []byte("/..")
	strSlashDotSlash            = []byte("/./")
	strSlashDotDotSlash         = []byte("/../")
	strBackSlashDotDot          = []byte(`\..`)
	strBackSlashDotBackSlash    = []byte(`\.\`)
	strSlashDotDotBackSlash     = []byte(`/..\`)
	strBackSlashDotDotBackSlash = []byte(`\..\`)
	strCRLF                     = []byte("\r\n")
	strHTTP                     = []byte("http")
	strHTTPS                    = []byte("https")
	strHTTP10                   = []byte("HTTP/1.0")
	strHTTP11                   = []byte("HTTP/1.1")
	strColon                    = []byte(":")
	strColonSlashSlash          = []byte("://")
	strColonSpace               = []byte(": ")
	strCommaSpace               = []byte(", ")
	strGMT                      = []byte("GMT")
	"path/filepath"
	if filepath.Separator == '\\' {
		// remove \.\ parts
		b = dst
		for {
			n := bytes.Index(b, strBackSlashDotBackSlash)
			if n < 0 {
				break
			}
			nn := n + len(strSlashDotSlash) - 1
			copy(b[n:], b[nn:])
			b = b[:len(b)-nn+n]
		}

		// remove /foo/..\ parts
		for {
			n := bytes.Index(b, strSlashDotDotBackSlash)
			if n < 0 {
				break
			}
			nn := bytes.LastIndexByte(b[:n], '/')
			if nn < 0 {
				nn = 0
			}
			n += len(strSlashDotDotBackSlash) - 1
			copy(b[nn:], b[n:])
			b = b[:len(b)-n+nn]
		}

		// remove /foo\..\ parts
		for {
			n := bytes.Index(b, strBackSlashDotDotBackSlash)
			if n < 0 {
				break
			}
			nn := bytes.LastIndexByte(b[:n], '/')
			if nn < 0 {
				nn = 0
			}
			n += len(strBackSlashDotDotBackSlash) - 1
			copy(b[nn:], b[n:])
			b = b[:len(b)-n+nn]
		}

		// remove trailing \foo\..
		n := bytes.LastIndex(b, strBackSlashDotDot)
		if n >= 0 && n+len(strSlashDotDot) == len(b) {
			nn := bytes.LastIndexByte(b[:n], '/')
			if nn < 0 {
				return append(dst[:0], strSlash...)
			}
			b = b[:nn+1]
		}
	}