diff --git a/internal/http/response/html/html.go b/internal/http/response/html/html.go index 001b7ede..fe21b0a2 100644 --- a/internal/http/response/html/html.go +++ b/internal/http/response/html/html.go @@ -4,6 +4,7 @@ package html // import "miniflux.app/v2/internal/http/response/html" import ( + "html" "log/slog" "net/http" @@ -38,9 +39,9 @@ func ServerError(w http.ResponseWriter, r *http.Request, err error) { builder := response.New(w, r) builder.WithStatus(http.StatusInternalServerError) builder.WithHeader("Content-Security-Policy", response.ContentSecurityPolicyForUntrustedContent) - builder.WithHeader("Content-Type", "text/html; charset=utf-8") + builder.WithHeader("Content-Type", "text/plain; charset=utf-8") builder.WithHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store") - builder.WithBody(err) + builder.WithBody(html.EscapeString(err.Error())) builder.Write() } @@ -62,9 +63,9 @@ func BadRequest(w http.ResponseWriter, r *http.Request, err error) { builder := response.New(w, r) builder.WithStatus(http.StatusBadRequest) builder.WithHeader("Content-Security-Policy", response.ContentSecurityPolicyForUntrustedContent) - builder.WithHeader("Content-Type", "text/html; charset=utf-8") + builder.WithHeader("Content-Type", "text/plain; charset=utf-8") builder.WithHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store") - builder.WithBody(err) + builder.WithBody(html.EscapeString(err.Error())) builder.Write() } diff --git a/internal/http/response/html/html_test.go b/internal/http/response/html/html_test.go index 3acbd8ce..830255fd 100644 --- a/internal/http/response/html/html_test.go +++ b/internal/http/response/html/html_test.go @@ -58,7 +58,7 @@ func TestServerErrorResponse(t *testing.T) { w := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ServerError(w, r, errors.New("Some error")) + ServerError(w, r, errors.New("Some error with injected HTML ")) }) handler.ServeHTTP(w, r) @@ -69,13 +69,13 @@ func TestServerErrorResponse(t *testing.T) { t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode) } - expectedBody := `Some error` + expectedBody := `Some error with injected HTML <script>alert('XSS')</script>` actualBody := w.Body.String() if actualBody != expectedBody { t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody) } - expectedContentType := "text/html; charset=utf-8" + expectedContentType := "text/plain; charset=utf-8" actualContentType := resp.Header.Get("Content-Type") if actualContentType != expectedContentType { t.Fatalf(`Unexpected content type, got %q instead of %q`, actualContentType, expectedContentType) @@ -91,7 +91,7 @@ func TestBadRequestResponse(t *testing.T) { w := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - BadRequest(w, r, errors.New("Some error")) + BadRequest(w, r, errors.New("Some error with injected HTML ")) }) handler.ServeHTTP(w, r) @@ -102,13 +102,13 @@ func TestBadRequestResponse(t *testing.T) { t.Fatalf(`Unexpected status code, got %d instead of %d`, resp.StatusCode, expectedStatusCode) } - expectedBody := `Some error` + expectedBody := `Some error with injected HTML <script>alert('XSS')</script>` actualBody := w.Body.String() if actualBody != expectedBody { t.Fatalf(`Unexpected body, got %s instead of %s`, actualBody, expectedBody) } - expectedContentType := "text/html; charset=utf-8" + expectedContentType := "text/plain; charset=utf-8" actualContentType := resp.Header.Get("Content-Type") if actualContentType != expectedContentType { t.Fatalf(`Unexpected content type, got %q instead of %q`, actualContentType, expectedContentType)