From a1600af967b7eaa77360339b402b447855c24915 Mon Sep 17 00:00:00 2001 From: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:49:30 +0200 Subject: [PATCH] expfmt: fix nil pointer panic when parsing empty braces "{}" The text exposition parser panics with a nil pointer dereference when it encounters a closing brace before any metric name has been read, e.g. for the input "{}". In startOfLine a leading "{" sets currentMetricIsInsideBraces and jumps straight to label parsing without going through readingMetricName, so currentMF/currentMetric are still nil when startLabelName dereferences currentMetric on the "}" branch. Since TextToMetricFamilies is used to decode untrusted scrape payloads, a malicious or compromised target could crash any consumer that does not wrap the parser in its own recover(). Guard the "}" branch on currentMF == nil and return a parse error, mirroring the existing guard in startLabelValue. currentMF is checked rather than currentMetric because reset only clears currentMF between parses. Introduced in #670. Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> --- expfmt/text_parse.go | 10 ++++++++++ expfmt/text_parse_test.go | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/expfmt/text_parse.go b/expfmt/text_parse.go index 00c8841a..4ce1f40b 100644 --- a/expfmt/text_parse.go +++ b/expfmt/text_parse.go @@ -339,6 +339,16 @@ func (p *TextParser) startLabelName() stateFn { return nil // Unexpected end of input. } if p.currentByte == '}' { + if p.currentMF == nil { + // The closing brace was reached before any metric name was read, + // e.g. for the input "{}". There is no metric to attach labels to, + // so this is a malformed exposition. This mirrors the guard in + // startLabelValue. currentMF (not currentMetric) is checked because + // reset only clears currentMF between parses. + p.parseError("invalid metric name") + p.currentLabelPairs = nil + return nil + } p.currentMetric.Label = append(p.currentMetric.Label, p.currentLabelPairs...) p.currentLabelPairs = nil if p.skipBlankTab(); p.err != nil { diff --git a/expfmt/text_parse_test.go b/expfmt/text_parse_test.go index edcee13a..e915fb98 100644 --- a/expfmt/text_parse_test.go +++ b/expfmt/text_parse_test.go @@ -1332,6 +1332,12 @@ request_duration_microseconds_count 2693 `, errUTF8: `text format parsing error in line 5: negative bucket population for histogram "request_duration_microseconds"`, }, + // 47: Empty braces with no metric name (regression test for a nil + // pointer dereference in startLabelName). + { + in: `{} 3.14`, + errUTF8: "text format parsing error in line 1: invalid metric name", + }, } for i, scenario := range scenarios { parser.scheme = model.UTF8Validation