Skip to content

Commit ed3cf08

Browse files
authored
fix: sanitize User-Agent to valid UTF-8 before using as Prometheus label value (#21162)
1 parent fc48c92 commit ed3cf08

2 files changed

Lines changed: 18 additions & 0 deletions

File tree

‎pkg/loghttp/push/push.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ func ParseRequest(logger log.Logger, userID string, maxRecvMsgSize int, maxDecom
269269
}
270270

271271
userAgent := r.Header.Get("User-Agent")
272+
// Sanitize the User-Agent to valid UTF-8 to prevent prometheus from panicking
273+
// when it's used as a label value in WithLabelValues.
274+
userAgent = strings.ToValidUTF8(userAgent, "")
272275
if userAgent != "" {
273276
logValues = append(logValues, "userAgent", strings.TrimSpace(userAgent))
274277
}

‎pkg/loghttp/push/push_test.go‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ func TestParseRequest(t *testing.T) {
7878
body string
7979
contentType string
8080
contentEncoding string
81+
userAgent string
8182
valid bool
8283
enableServiceDiscovery bool
8384
expectedStructuredMetadataBytes map[string]int
@@ -339,6 +340,17 @@ func TestParseRequest(t *testing.T) {
339340
expectedLabels: []labels.Labels{labels.FromStrings("foo", "bar2", "environment", "prod")},
340341
expectedStructuredMetadataBytes: map[string]int{"prod": len("name1") + len("value1")},
341342
},
343+
{
344+
path: `/loki/api/v1/push`,
345+
body: fmt.Sprintf(`{"streams": [{"stream": {"foo": "bar2"}, "values": [["%d", "fizzbuzz"]]}]}`, time.Now().UnixNano()),
346+
contentType: `application/json`,
347+
userAgent: "\xe5\xe5\xe5\xe5\xe5\xe5; Intel Mac OS X 10.15; rv:148.0) Gecko/20100101 Firefox/148.0",
348+
valid: true,
349+
expectedBytes: map[string]int{"": len("fizzbuzz")},
350+
expectedLines: map[string]int{"": 1},
351+
expectedBytesUsageTracker: map[string]float64{`{foo="bar2"}`: float64(len("fizzbuzz"))},
352+
expectedLabels: []labels.Labels{labels.FromStrings("foo", "bar2")},
353+
},
342354
} {
343355
t.Run(fmt.Sprintf("test %d", index), func(t *testing.T) {
344356
streamResolver := newMockStreamResolver("fake", test.fakeLimits)
@@ -357,6 +369,9 @@ func TestParseRequest(t *testing.T) {
357369
if len(test.contentEncoding) > 0 {
358370
request.Header.Add("Content-Encoding", test.contentEncoding)
359371
}
372+
if len(test.userAgent) > 0 {
373+
request.Header.Set("User-Agent", test.userAgent)
374+
}
360375

361376
tracker := NewMockTracker()
362377
data, stats, err := ParseRequest(

0 commit comments

Comments
 (0)