From 6ae45794b9fe8d7a50d4360115429d8f4dd2315a Mon Sep 17 00:00:00 2001 From: Daniel Blando Date: Thu, 30 Apr 2026 10:28:02 -0700 Subject: [PATCH 1/3] security: fix stored XSS in alertmanager and storegateway status pages Replace text/template with html/template in alertmanager_http.go and gateway_http.go to auto-escape HTML special characters. This prevents stored XSS via crafted gossip member names rendered on status pages. The html/template package has an identical API to text/template but automatically escapes HTML, JS, and URI contexts. Add TestStatusHandler_HTMLEscaping to verify XSS payloads are escaped. Fixes #22 Signed-off-by: Daniel Blando --- pkg/alertmanager/alertmanager_http.go | 2 +- pkg/alertmanager/alertmanager_http_test.go | 27 ++++++++++++++++++++++ pkg/storegateway/gateway_http.go | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/pkg/alertmanager/alertmanager_http.go b/pkg/alertmanager/alertmanager_http.go index 2a313b3700b..fdb035c1078 100644 --- a/pkg/alertmanager/alertmanager_http.go +++ b/pkg/alertmanager/alertmanager_http.go @@ -2,7 +2,7 @@ package alertmanager import ( "net/http" - "text/template" + "html/template" "github.com/go-kit/log/level" diff --git a/pkg/alertmanager/alertmanager_http_test.go b/pkg/alertmanager/alertmanager_http_test.go index b31173dc340..7e4eed22d91 100644 --- a/pkg/alertmanager/alertmanager_http_test.go +++ b/pkg/alertmanager/alertmanager_http_test.go @@ -1,6 +1,7 @@ package alertmanager import ( + "bytes" "io" "net/http/httptest" "testing" @@ -12,6 +13,32 @@ import ( "github.com/stretchr/testify/require" ) +func TestStatusHandler_HTMLEscaping(t *testing.T) { + // Verify that html/template escapes XSS payloads in the status page. + xssPayload := `` + + var buf bytes.Buffer + err := statusTemplate.Execute(&buf, struct { + ClusterInfo map[string]any + }{ + ClusterInfo: map[string]any{ + "self": map[string]any{ + "Name": xssPayload, + "Addr": "127.0.0.1", + "Port": "9094", + }, + "members": []map[string]any{ + {"Name": xssPayload, "Addr": "127.0.0.1:9094"}, + }, + }, + }) + require.NoError(t, err) + + content := buf.String() + require.NotContains(t, content, xssPayload, "XSS payload must be escaped by html/template") + require.Contains(t, content, "<script>", "HTML special characters must be escaped") +} + func TestMultitenantAlertmanager_GetStatusHandler(t *testing.T) { ctx := t.Context() var peer *cluster.Peer diff --git a/pkg/storegateway/gateway_http.go b/pkg/storegateway/gateway_http.go index a823eb6f403..5ea408aa271 100644 --- a/pkg/storegateway/gateway_http.go +++ b/pkg/storegateway/gateway_http.go @@ -2,7 +2,7 @@ package storegateway import ( "net/http" - "text/template" + "html/template" "github.com/go-kit/log/level" From 82ff9841a5a81328fbdb4a2c5b50c1c0e458ae50 Mon Sep 17 00:00:00 2001 From: Friedrich Gonzalez <1517449+friedrichg@users.noreply.github.com> Date: Sat, 2 May 2026 06:41:11 -0700 Subject: [PATCH 2/3] Fix lint Signed-off-by: Friedrich Gonzalez <1517449+friedrichg@users.noreply.github.com> --- pkg/alertmanager/alertmanager_http.go | 2 +- pkg/storegateway/gateway_http.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/alertmanager/alertmanager_http.go b/pkg/alertmanager/alertmanager_http.go index fdb035c1078..2062ff8b7c9 100644 --- a/pkg/alertmanager/alertmanager_http.go +++ b/pkg/alertmanager/alertmanager_http.go @@ -1,8 +1,8 @@ package alertmanager import ( - "net/http" "html/template" + "net/http" "github.com/go-kit/log/level" diff --git a/pkg/storegateway/gateway_http.go b/pkg/storegateway/gateway_http.go index 5ea408aa271..bdbdc647fb7 100644 --- a/pkg/storegateway/gateway_http.go +++ b/pkg/storegateway/gateway_http.go @@ -1,8 +1,8 @@ package storegateway import ( - "net/http" "html/template" + "net/http" "github.com/go-kit/log/level" From ec1293861eba5a1ac8ac9e31c142d8b2c48b0a8f Mon Sep 17 00:00:00 2001 From: Daniel Blando Date: Sat, 2 May 2026 14:17:30 -0700 Subject: [PATCH 3/3] changelog Signed-off-by: Daniel Blando --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a3acffb6ed..d56a1e916ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * [BUGFIX] Config: Mask Swift, etcd, Redis, and HTTP basic-auth credentials on the `/config` endpoint. #7473 * [BUGFIX] Memberlist: Drop incoming TCP transport packets when digest verification fails, preventing corrupted payloads from being forwarded. #7474 * [BUGFIX] Compactor: Fix stale `cortex_bucket_index_last_successful_update_timestamp_seconds` metric not being cleaned up when tenant ownership changes due to ring rebalancing. This caused false alarms on bucket index update rate when a tenant moved between compactors. #7485 +* [BUGFIX] Security: Fix stored XSS vulnerability in Alertmanager and Store Gateway status pages by replacing `text/template` with `html/template`. #7512 ## 1.21.0 2026-04-24