From 503c2d7ea3da700c630c8257deadf70806485a03 Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Thu, 2 Apr 2026 00:19:29 +0300 Subject: [PATCH] fix(kubernetes): sanitize non-UTF-8 host in metrics (#7998) --- plugin/kubernetes/metrics.go | 15 +++++++++++++-- plugin/kubernetes/metrics_test.go | 27 +++++++++++++++++++++++++++ test/corefile_test.go | 16 ++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 plugin/kubernetes/metrics_test.go diff --git a/plugin/kubernetes/metrics.go b/plugin/kubernetes/metrics.go index caebffad6..024c77a1f 100644 --- a/plugin/kubernetes/metrics.go +++ b/plugin/kubernetes/metrics.go @@ -3,7 +3,9 @@ package kubernetes import ( "context" "net/url" + "strings" "time" + "unicode/utf8" "github.com/coredns/coredns/plugin" @@ -64,7 +66,7 @@ type latencyAdapter struct { } func (l *latencyAdapter) Observe(_ context.Context, verb string, u url.URL, latency time.Duration) { - l.m.WithLabelValues(verb, u.Host).Observe(latency.Seconds()) + l.m.WithLabelValues(verb, sanitizeLabelValue(u.Host)).Observe(latency.Seconds()) } type resultAdapter struct { @@ -72,5 +74,14 @@ type resultAdapter struct { } func (r *resultAdapter) Increment(_ context.Context, code, method, host string) { - r.m.WithLabelValues(code, method, host).Inc() + r.m.WithLabelValues(code, method, sanitizeLabelValue(host)).Inc() +} + +// sanitizeLabelValue ensures the string is valid UTF-8, which is required by +// Prometheus for label values. Invalid bytes are replaced with U+FFFD. +func sanitizeLabelValue(s string) string { + if utf8.ValidString(s) { + return s + } + return strings.ToValidUTF8(s, "\uFFFD") } diff --git a/plugin/kubernetes/metrics_test.go b/plugin/kubernetes/metrics_test.go new file mode 100644 index 000000000..5907405d8 --- /dev/null +++ b/plugin/kubernetes/metrics_test.go @@ -0,0 +1,27 @@ +package kubernetes + +import "testing" + +func TestSanitizeLabelValue(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + {"valid ASCII", "example.com", "example.com"}, + {"valid UTF-8", "例え.jp", "例え.jp"}, + {"empty string", "", ""}, + {"invalid single byte", "host\xff:443", "host\uFFFD:443"}, + {"consecutive invalid bytes", "\xff\xfe\xfd", "\uFFFD"}, + {"mixed valid and invalid", "ok\xffok\xfeok", "ok\uFFFDok\uFFFDok"}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := sanitizeLabelValue(tc.input) + if got != tc.expected { + t.Errorf("sanitizeLabelValue(%q) = %q, want %q", tc.input, got, tc.expected) + } + }) + } +} diff --git a/test/corefile_test.go b/test/corefile_test.go index c93114542..840833727 100644 --- a/test/corefile_test.go +++ b/test/corefile_test.go @@ -25,6 +25,22 @@ acl "hosts#\x90\xD0{lc\x0C{\n" + "'{mport\xEF1\x0C}\x0B''", }, + { + // A kubernetes endpoint URL with invalid UTF-8 caused a + // panic in Prometheus WithLabelValues. + // See OSS-Fuzz issue: https://issues.oss-fuzz.com/issues/498472468 + name: "FuzzCore_InvalidUTF8InKubernetesEndpoint", + corefile: "\xf6\xe6*S65558::65535\n" + + "kubernetes idd\x0cd\xc8:0\x00,\x13" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd" + + "\x00\x00\x00\x00\x00\x00\x00-\x00\x00\x00\x00" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + "\t{\tendpoint m\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xffFFFFFF%FFFFFFFF\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + "\xff\xff\tuil{ticll{ticl\x00,1:*\x0cd}\x0c}", + }, } for _, tc := range cases {