From 9a29bc7538e089763eb6607001df4bb986dcc0f0 Mon Sep 17 00:00:00 2001 From: SungJin1212 Date: Thu, 18 Jun 2026 10:42:48 +0900 Subject: [PATCH] fix handling of trailing commas in SecretStringSliceCSV.Set() Signed-off-by: SungJin1212 --- CHANGELOG.md | 1 + pkg/util/flagext/secretstringslicecsv.go | 20 +++++++++++-- pkg/util/flagext/secretstringslicecsv_test.go | 28 +++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8842af32f..bbf36ec4ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ * [BUGFIX] Distributor: Release the push worker pool goroutines on shutdown by stopping the async executor during the stopping phase when `-distributor.num-push-workers` is set. #7602 * [BUGFIX] Querier: Fix flake in integration tests TestQuerierWithStoreGatewayDataBytesLimits and TestQuerierWithBlocksStorageLimits by waiting for the querier to see the store-gateway ACTIVE in the ring before querying. #7614 * [BUGFIX] Ruler: Register xfunctions (xincrease, xrate, xdelta) in the global parser before loading rule files. #7621 +* [BUGFIX] Security: Reject empty entries in `-distributor.sign-write-requests-keys` caused by stray or trailing commas (e.g. `newkey,`). Previously these were silently accepted and produced an empty signing key, which downgraded HMAC stream-push authentication to a forgeable signature. Misconfigured flags now fail at process startup; audit your configs before upgrading. #7587 ## 1.21.0 2026-04-24 diff --git a/pkg/util/flagext/secretstringslicecsv.go b/pkg/util/flagext/secretstringslicecsv.go index 0a1dea7834..e48fc070c4 100644 --- a/pkg/util/flagext/secretstringslicecsv.go +++ b/pkg/util/flagext/secretstringslicecsv.go @@ -1,6 +1,9 @@ package flagext -import "strings" +import ( + "errors" + "strings" +) // SecretStringSliceCSV is a slice of strings that is parsed from a comma-separated string. // It implements flag.Value and yaml Marshalers, but masks the value when marshaled to YAML @@ -15,12 +18,25 @@ func (v SecretStringSliceCSV) String() string { } // Set implements flag.Value +// Each comma-separated entry is trimmed of surrounding whitespace. +// Empty entries (after trimming) are rejected with an error. func (v *SecretStringSliceCSV) Set(s string) error { if s == "" { v.values = nil return nil } - v.values = strings.Split(s, ",") + parts := strings.Split(s, ",") + values := make([]string, 0, len(parts)) + for _, p := range parts { + p = strings.TrimSpace(p) + if p == "" { + // Do not include the original input value in the error message + // to avoid accidentally exposing secret values. + return errors.New("invalid value: empty entry after trimming") + } + values = append(values, p) + } + v.values = values return nil } diff --git a/pkg/util/flagext/secretstringslicecsv_test.go b/pkg/util/flagext/secretstringslicecsv_test.go index 58772e28c1..fad17c3f05 100644 --- a/pkg/util/flagext/secretstringslicecsv_test.go +++ b/pkg/util/flagext/secretstringslicecsv_test.go @@ -44,4 +44,32 @@ func TestSecretStringSliceCSV(t *testing.T) { require.NoError(t, s.Keys.Set("")) assert.Equal(t, []string(nil), s.Keys.Value()) }) + + t.Run("trailing comma is rejected", func(t *testing.T) { + var s TestStruct + err := s.Keys.Set("newkey,") + require.Error(t, err, "trailing comma must produce an error") + assert.Nil(t, s.Keys.Value(), "values must not be updated on error") + }) + + t.Run("leading comma is rejected", func(t *testing.T) { + var s TestStruct + require.Error(t, s.Keys.Set(",newkey")) + }) + + t.Run("double comma is rejected", func(t *testing.T) { + var s TestStruct + require.Error(t, s.Keys.Set("newkey,,oldkey")) + }) + + t.Run("whitespace-only entry is rejected", func(t *testing.T) { + var s TestStruct + require.Error(t, s.Keys.Set("newkey, ,oldkey")) + }) + + t.Run("surrounding whitespace is trimmed from valid entries", func(t *testing.T) { + var s TestStruct + require.NoError(t, s.Keys.Set(" key1 , key2 ")) + assert.Equal(t, []string{"key1", "key2"}, s.Keys.Value()) + }) }