Misusing filepath.Clean for Security
Using filepath.Clean() believing it prevents path traversal attacks.
Path traversal vulnerabilities occur when applications use filepath.Clean() as a security control, mistakenly believing it prevents directory traversal. filepath.Clean() only normalizes paths but does NOT enforce directory boundaries, allowing attackers to access files outside intended directories using '../' sequences or absolute paths.
package main
import (
"io/ioutil"
"net/http"
"path/filepath"
)
func fileHandler(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
baseDir := "/var/www/uploads/"
// VULNERABLE: filepath.Clean does NOT prevent traversal!
cleanPath := filepath.Clean(filename)
fullPath := baseDir + cleanPath
content, err := ioutil.ReadFile(fullPath)
if err != nil {
http.Error(w, "File not found", 404)
return
}
w.Write(content)
}
// Attack: file=../../../etc/passwd
// Clean result: ../../../etc/passwd (still traverses!)
// Full path: /var/www/uploads/../../../etc/passwd
// Resolves to: /etc/passwdpackage main
import (
"errors"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
)
func fileHandler(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
baseDir := "/var/www/uploads/"
// SECURE: Validate path stays within base directory
safePath, err := secureJoin(baseDir, filename)
if err != nil {
http.Error(w, "Invalid file path", 400)
return
}
content, err := ioutil.ReadFile(safePath)
if err != nil {
http.Error(w, "File not found", 404)
return
}
w.Write(content)
}
func secureJoin(base, userPath string) (string, error) {
// Get absolute path of base
absBase, err := filepath.Abs(base)
if err != nil {
return "", err
}
// Join and get absolute path
joined := filepath.Join(absBase, userPath)
absJoined, err := filepath.Abs(joined)
if err != nil {
return "", err
}
// Validate it stays within base directory
if !strings.HasPrefix(absJoined, absBase) {
return "", errors.New("path traversal detected")
}
return absJoined, nil
}The vulnerable code uses filepath.Clean() thinking it prevents path traversal, but Clean only normalizes paths and does NOT enforce directory boundaries. The secure version validates that the resolved absolute path starts with the base directory, rejecting any path that escapes it.
Using filepath.Clean() believing it prevents path traversal attacks.
Sourcery automatically identifies path traversal via filepath.clean misuse in go and many other security issues in your codebase.