Skip to content

Commit 54d3621

Browse files
Potential fix for code scanning alert no. 9: Uncontrolled data used in path expression
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent b427711 commit 54d3621

1 file changed

Lines changed: 29 additions & 16 deletions

File tree

cmd/main.go

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ import (
1919
"github.com/tikv/client-go/v2/rawkv"
2020
)
2121

22+
// isPathWithinRoot returns true if candidate is the same as root or a descendant of it.
23+
func isPathWithinRoot(root, candidate string) (string, bool) {
24+
cleanRoot := filepath.Clean(root)
25+
absRoot, err := filepath.Abs(cleanRoot)
26+
if err != nil {
27+
return "", false
28+
}
29+
absCandidate, err := filepath.Abs(candidate)
30+
if err != nil {
31+
return "", false
32+
}
33+
if absCandidate == absRoot || strings.HasPrefix(absCandidate, absRoot+string(os.PathSeparator)) {
34+
return absCandidate, true
35+
}
36+
return "", false
37+
}
38+
2239
func main() {
2340
// Read PD addresses from env: TIKV_PD_ADDRS="127.0.0.1:2379|My Cluster 1,127.0.0.1:2381;server-2.com:2379|Cluster 2"
2441
pdAddrsEnv := os.Getenv("TIKV_PD_ADDRS")
@@ -78,8 +95,8 @@ func main() {
7895
// In Docker, we will copy the built 'out' directory to 'public'
7996
staticDir := "./public"
8097
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
81-
// Resolve the static directory to an absolute path
82-
staticRoot, err := filepath.Abs(staticDir)
98+
// Resolve the static directory to an absolute, cleaned path
99+
staticRoot, err := filepath.Abs(filepath.Clean(staticDir))
83100
if err != nil {
84101
http.Error(w, "Internal server error", http.StatusInternalServerError)
85102
return
@@ -99,27 +116,23 @@ func main() {
99116
absPath := filepath.Join(staticRoot, relPath)
100117

101118
// Ensure the resolved path is within staticRoot
102-
absPath, err = filepath.Abs(absPath)
103-
if err != nil {
104-
http.Error(w, "Internal server error", http.StatusInternalServerError)
105-
return
106-
}
107-
if absPath != staticRoot && !strings.HasPrefix(absPath, staticRoot+string(os.PathSeparator)) {
119+
resolvedPath, ok := isPathWithinRoot(staticRoot, absPath)
120+
if !ok {
108121
http.Error(w, "Invalid path", http.StatusBadRequest)
109122
return
110123
}
111124

112125
// Check if exact file exists (e.g., /favicon.ico, /_next/static/...)
113-
if info, err := os.Stat(absPath); err == nil && !info.IsDir() {
114-
http.ServeFile(w, r, absPath)
126+
if info, err := os.Stat(resolvedPath); err == nil && !info.IsDir() {
127+
http.ServeFile(w, r, resolvedPath)
115128
return
116129
}
117130

118131
// For routes like /metrics, try serving metrics.html (Next.js static export)
119132
if r.URL.Path != "/" {
120-
htmlPath := absPath + ".html"
121-
htmlPathAbs, err := filepath.Abs(htmlPath)
122-
if err != nil || !strings.HasPrefix(htmlPathAbs, staticRoot+string(os.PathSeparator)) {
133+
htmlPath := resolvedPath + ".html"
134+
htmlPathAbs, ok := isPathWithinRoot(staticRoot, htmlPath)
135+
if !ok {
123136
http.Error(w, "Invalid path", http.StatusBadRequest)
124137
return
125138
}
@@ -129,9 +142,9 @@ func main() {
129142
}
130143

131144
// Also check for directory with index.html (e.g., /metrics/index.html)
132-
indexPath := filepath.Join(absPath, "index.html")
133-
indexPathAbs, err := filepath.Abs(indexPath)
134-
if err != nil || !strings.HasPrefix(indexPathAbs, staticRoot+string(os.PathSeparator)) {
145+
indexPath := filepath.Join(resolvedPath, "index.html")
146+
indexPathAbs, ok := isPathWithinRoot(staticRoot, indexPath)
147+
if !ok {
135148
http.Error(w, "Invalid path", http.StatusBadRequest)
136149
return
137150
}

0 commit comments

Comments
 (0)