From a5a84ff7852b2382b607957bed4c644b813b57f3 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Tue, 10 Mar 2026 13:17:28 +0300 Subject: [PATCH] watchdog: reorder operations; make `SafeFileServer` consistent Signed-off-by: NotAShelf Change-Id: I03ec1167eb7cb8e7801b5a0778aa60756a6a6964 --- cmd/watchdog/root.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cmd/watchdog/root.go b/cmd/watchdog/root.go index f3301e1..38b82ac 100644 --- a/cmd/watchdog/root.go +++ b/cmd/watchdog/root.go @@ -285,8 +285,18 @@ func sanitizePathForLog(path string) string { func safeFileServer(root string, blockedRequests *prometheus.CounterVec) http.Handler { fs := http.FileServer(http.Dir(root)) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Clean the path - path := filepath.Clean(r.URL.Path) + // Strip the /web/ prefix first, then clean the path + // This ensures validation runs on the same path that will be served + prefix := "/web/" + if !strings.HasPrefix(r.URL.Path, prefix) { + // This shouldn't happen if routing is correct, but handle it anyway + http.NotFound(w, r) + return + } + + // Get the path after the prefix and clean it + relPath := strings.TrimPrefix(r.URL.Path, prefix) + path := filepath.Clean("/" + relPath) // Block directory listings if strings.HasSuffix(path, "/") { @@ -305,6 +315,7 @@ func safeFileServer(root string, blockedRequests *prometheus.CounterVec) http.Ha return } // Block common sensitive files + // FIXME: make this a configuration option lower := strings.ToLower(segment) if strings.Contains(lower, ".env") || strings.Contains(lower, "config") || @@ -326,6 +337,8 @@ func safeFileServer(root string, blockedRequests *prometheus.CounterVec) http.Ha return } - http.StripPrefix("/web/", fs).ServeHTTP(w, r) + // Serve the file + // Validation and serving use the same cleaned path + fs.ServeHTTP(w, r) }) }