Skip to content

Commit af9c40c

Browse files
security: fix stored XSS in alertmanager and storegateway status pages (#7512)
* 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 <ddeluigg@amazon.com> * Fix lint Signed-off-by: Friedrich Gonzalez <1517449+friedrichg@users.noreply.github.com> * changelog Signed-off-by: Daniel Blando <ddeluigg@amazon.com> --------- Signed-off-by: Daniel Blando <ddeluigg@amazon.com> Signed-off-by: Friedrich Gonzalez <1517449+friedrichg@users.noreply.github.com> Co-authored-by: Friedrich Gonzalez <1517449+friedrichg@users.noreply.github.com>
1 parent a13e3d9 commit af9c40c

4 files changed

Lines changed: 30 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* [BUGFIX] Config: Mask Swift, etcd, Redis, and HTTP basic-auth credentials on the `/config` endpoint. #7473
3535
* [BUGFIX] Memberlist: Drop incoming TCP transport packets when digest verification fails, preventing corrupted payloads from being forwarded. #7474
3636
* [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
37+
* [BUGFIX] Security: Fix stored XSS vulnerability in Alertmanager and Store Gateway status pages by replacing `text/template` with `html/template`. #7512
3738

3839
## 1.21.0 2026-04-24
3940

pkg/alertmanager/alertmanager_http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package alertmanager
22

33
import (
4+
"html/template"
45
"net/http"
5-
"text/template"
66

77
"github.com/go-kit/log/level"
88

pkg/alertmanager/alertmanager_http_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package alertmanager
22

33
import (
4+
"bytes"
45
"io"
56
"net/http/httptest"
67
"testing"
@@ -12,6 +13,32 @@ import (
1213
"github.com/stretchr/testify/require"
1314
)
1415

16+
func TestStatusHandler_HTMLEscaping(t *testing.T) {
17+
// Verify that html/template escapes XSS payloads in the status page.
18+
xssPayload := `<script>alert("xss")</script>`
19+
20+
var buf bytes.Buffer
21+
err := statusTemplate.Execute(&buf, struct {
22+
ClusterInfo map[string]any
23+
}{
24+
ClusterInfo: map[string]any{
25+
"self": map[string]any{
26+
"Name": xssPayload,
27+
"Addr": "127.0.0.1",
28+
"Port": "9094",
29+
},
30+
"members": []map[string]any{
31+
{"Name": xssPayload, "Addr": "127.0.0.1:9094"},
32+
},
33+
},
34+
})
35+
require.NoError(t, err)
36+
37+
content := buf.String()
38+
require.NotContains(t, content, xssPayload, "XSS payload must be escaped by html/template")
39+
require.Contains(t, content, "&lt;script&gt;", "HTML special characters must be escaped")
40+
}
41+
1542
func TestMultitenantAlertmanager_GetStatusHandler(t *testing.T) {
1643
ctx := t.Context()
1744
var peer *cluster.Peer

pkg/storegateway/gateway_http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package storegateway
22

33
import (
4+
"html/template"
45
"net/http"
5-
"text/template"
66

77
"github.com/go-kit/log/level"
88

0 commit comments

Comments
 (0)