From 09b6ccd5c4b792b43fda19fd8d173096d4d2d59b Mon Sep 17 00:00:00 2001 From: SungJin1212 Date: Mon, 18 May 2026 21:45:07 +0900 Subject: [PATCH] validate tenant IDs in IsAllowed Signed-off-by: SungJin1212 --- CHANGELOG.md | 1 + pkg/util/users/allowed_tenants.go | 3 +-- pkg/util/users/allowed_tenants_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f86f69e383..0018940d564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ * [ENHANCEMENT] Distributor: Add HMAC-SHA256 stream authentication for `PushStream` via `-distributor.sign-write-requests-keys`. #7475 * [ENHANCEMENT] Instrument Ingester CPU profile with source for read APIs. #7494 * [ENHANCEMENT] Ingester: Convert expanded postings cache from FIFO to LRU eviction to retain frequently-queried entries under memory pressure. #7510 +* [ENHANCEMENT] Validate tenantID in `IsAllowed` to reject tenant IDs with unsupported characters, length exceeding 150 characters, path traversal segments (`.` or `..`), and reserved names (`__markers__`, `user-index.json.gz`). #7525 * [BUGFIX] Querier: Fix queryWithRetry and labelsWithRetry returning (nil, nil) on cancelled context by propagating ctx.Err(). #7370 * [BUGFIX] Metrics Helper: Fix non-deterministic bucket order in merged histograms by sorting buckets after map iteration, matching Prometheus client library behavior. #7380 * [BUGFIX] Distributor: Return HTTP 401 Unauthorized when tenant ID resolution fails in the Prometheus Remote Write 2.0 path. #7389 diff --git a/pkg/util/users/allowed_tenants.go b/pkg/util/users/allowed_tenants.go index 18f68f18e25..6d60479232d 100644 --- a/pkg/util/users/allowed_tenants.go +++ b/pkg/util/users/allowed_tenants.go @@ -34,8 +34,7 @@ func NewAllowedTenants(enabled []string, disabled []string) *AllowedTenants { } func (a *AllowedTenants) IsAllowed(tenantID string) bool { - if tenantID == GlobalMarkersDir { - // __markers__ is reserved for global markers and no tenant should be allowed to have that name. + if err := ValidTenantID(tenantID); err != nil { return false } diff --git a/pkg/util/users/allowed_tenants_test.go b/pkg/util/users/allowed_tenants_test.go index 53c5a7e5879..662c696e0e2 100644 --- a/pkg/util/users/allowed_tenants_test.go +++ b/pkg/util/users/allowed_tenants_test.go @@ -1,6 +1,7 @@ package users import ( + "strings" "testing" "github.com/stretchr/testify/require" @@ -45,3 +46,26 @@ func TestAllowedTenants_Nil(t *testing.T) { require.True(t, a.IsAllowed("B")) require.True(t, a.IsAllowed("C")) } + +func TestAllowedTenants_InvalidTenantID(t *testing.T) { + for _, tc := range []struct { + name string + tenantID string + }{ + {name: "markers dir", tenantID: GlobalMarkersDir}, + {name: "user-index", tenantID: "user-index.json.gz"}, + {name: "dot", tenantID: "."}, + {name: "double dot", tenantID: ".."}, + {name: "unsupported char pipe", tenantID: "tenant|id"}, + {name: "unsupported char space", tenantID: "tenant id"}, + {name: "too long", tenantID: strings.Repeat("a", 151)}, + } { + t.Run(tc.name, func(t *testing.T) { + // Invalid tenant IDs must be rejected regardless of AllowedTenants config. + require.False(t, NewAllowedTenants(nil, nil).IsAllowed(tc.tenantID), "NoConfig should reject invalid tenant") + require.False(t, NewAllowedTenants([]string{tc.tenantID}, nil).IsAllowed(tc.tenantID), "Enabled list should still reject invalid tenant") + var nilTenants *AllowedTenants + require.False(t, nilTenants.IsAllowed(tc.tenantID), "Nil AllowedTenants should reject invalid tenant") + }) + } +}