diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go index 53e3f73..27576de 100644 --- a/pkg/httpserver/httpserver.go +++ b/pkg/httpserver/httpserver.go @@ -73,6 +73,12 @@ func New(options *Options) (*HTTPServer, error) { dir = SandboxFileSystem{fs: http.Dir(options.Folder), RootFolder: options.Folder} } + // the python style handler reads the folder directly, without the + // sandbox file system + if options.Python && options.Sandbox { + return nil, errors.New("python style (-py) cannot be used with -sandbox") + } + var httpHandler http.Handler if options.Python { httpHandler = PythonStyle(dir.(http.Dir)) diff --git a/pkg/httpserver/pythonliststyle.go b/pkg/httpserver/pythonliststyle.go index ee6342f..1bda78b 100644 --- a/pkg/httpserver/pythonliststyle.go +++ b/pkg/httpserver/pythonliststyle.go @@ -3,6 +3,7 @@ package httpserver import ( "bytes" "fmt" + "html" "io" "net/http" "os" @@ -82,8 +83,10 @@ func (h *pythonStyleHandler) ServeHTTP(writer http.ResponseWriter, request *http http.ServeFile(writer, request, target) return } else { - _, _ = fmt.Fprintf(writer, htmlHeader, request.URL.Path) - _, _ = fmt.Fprintf(writer, "

Directory listing for %s

\n
\n", request.URL.Path) + // the path comes from the request: escape it before writing HTML + escapedPath := html.EscapeString(request.URL.Path) + _, _ = fmt.Fprintf(writer, htmlHeader, escapedPath) + _, _ = fmt.Fprintf(writer, "

Directory listing for %s

\n
\n", escapedPath) h.origWriter = writer http.ServeFile(h, request, target) _, _ = fmt.Fprint(writer, htmlFooter) diff --git a/test/pythonliststyle_test.go b/test/pythonliststyle_test.go index 0ee449a..f4c1eb9 100644 --- a/test/pythonliststyle_test.go +++ b/test/pythonliststyle_test.go @@ -74,3 +74,26 @@ func TestResponseNotFound(t *testing.T) { t.Errorf("want:\n%s\ngot:\n%s", want, got) } } + +func TestDirectoryListingEscapesPath(t *testing.T) { + py := httpserver.PythonStyle("./fixture/pythonliststyle") + + w := httptest.NewRecorder() + py.ServeHTTP(w, httptest.NewRequest("GET", "http://example.com/%3Cimg%20src=x%20onerror=alert(document.domain)%3E/..%2F", nil)) + b, _ := io.ReadAll(w.Result().Body) + + body := string(b) + if strings.Contains(body, "