flawopen.com/path-traversal/Go
How filepath.Join in Go fails to restrict file boundaries, and how to enforce containment using filepath.Clean and filepath.Rel.
Bayangkan pembaca kartu kunci hotel yang hanya boleh membuka kamar di lantai dua. Jika seorang tamu mengetik '../../master-safe' pada tombol pintu, kunci yang rentan keluar ke lorong dan membuka brankas utama milik manajer.
Web Application SecurityCWE-918.CWE-918Defense-in-DepthTitik akhir menerima nama file atau pengenal sumber daya dari parameter permintaan HTTP.
Penyerang menyisipkan urutan traversal seperti '../', '..%2f' atau jalur mutlak ke parameter file.
Backend menggabungkan nama file tanpa kanonisasi jalur dan tanpa memastikan target tetap dalam folder aman.
Sistem membaca dan mengalirkan file sensitif (misal: /etc/passwd atau rahasia konfigurasi) ke klien.
// VULNERABLE: filepath.Join does not prevent directory breakout
package main
import (
"net/http"
"os"
"path/filepath"
)
func downloadHandler(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
baseDir := "/var/app/public/files"
// Attacker input: "../../etc/shadow"
targetPath := filepath.Join(baseDir, filename)
data, err := os.ReadFile(targetPath)
if err != nil {
http.NotFound(w, r)
return
}
w.Write(data)
}
// HARDENED: Use filepath.Rel to verify target is strictly inside baseDir
package main
import (
"net/http"
"os"
"path/filepath"
"strings"
)
func downloadHandler(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
baseDir := "/var/app/public/files"
// 1. Resolve absolute paths
absBase, err := filepath.Abs(baseDir)
if err != nil {
http.Error(w, "Server error", http.StatusInternalServerError)
return
}
absTarget := filepath.Join(absBase, filepath.Clean("/"+filename))
// 2. Verify relative containment
rel, err := filepath.Rel(absBase, absTarget)
if err != nil || strings.HasPrefix(rel, "..") || rel == "." {
http.Error(w, "Access denied: Path Traversal detected", http.StatusForbidden)
return
}
data, err := os.ReadFile(absTarget)
if err != nil {
http.NotFound(w, r)
return
}
w.Write(data)
}
filepath.Clean().filepath.Rel().filepath.EvalSymlinks() where necessary.os.DirFS() which enforce chroot-like root boundaries.