diff --git a/analyzers/pathtraversal.go b/analyzers/pathtraversal.go index 9bf894d..ba9b72e 100644 --- a/analyzers/pathtraversal.go +++ b/analyzers/pathtraversal.go @@ -61,6 +61,9 @@ func PathTraversal() taint.Config { {Package: "io/ioutil", Method: "ReadDir"}, {Package: "path/filepath", Method: "Walk"}, {Package: "path/filepath", Method: "WalkDir"}, + // HTTP file-serving functions: user-controlled path = arbitrary file read + {Package: "net/http", Method: "ServeFile", CheckArgs: []int{2}}, + {Package: "net/http", Method: "ServeFileFS", CheckArgs: []int{3}}, }, Sanitizers: []taint.Sanitizer{ // filepath.Clean normalizes and removes traversal components diff --git a/testutils/g703_samples.go b/testutils/g703_samples.go index 4c89371..c3b0971 100644 --- a/testutils/g703_samples.go +++ b/testutils/g703_samples.go @@ -145,5 +145,44 @@ func handler(r *http.Request) { num, _ := strconv.Atoi(id) os.Open("/tmp/file" + strconv.Itoa(num)) } +`}, 0, gosec.NewConfig()}, + // True positive: http.ServeFile with user-controlled path + {[]string{` +package main + +import ( + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + path := r.URL.Query().Get("file") + http.ServeFile(w, r, path) +} +`}, 1, gosec.NewConfig()}, + // True positive: http.ServeFileFS with user-controlled path + {[]string{` +package main + +import ( + "net/http" + "os" +) + +func handler(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + http.ServeFileFS(w, r, os.DirFS("."), name) +} +`}, 1, gosec.NewConfig()}, + // True negative: http.ServeFile with hardcoded path + {[]string{` +package main + +import ( + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "static/index.html") +} `}, 0, gosec.NewConfig()}, }