From 7d74101708c3030a1f63f11cac6641f7f0812e44 Mon Sep 17 00:00:00 2001 From: szibis Date: Wed, 14 Oct 2026 17:29:35 +0200 Subject: [PATCH 1/2] fix: the translator no longer panics on a label name holding its key-list separator bytes A label filter after | json or | logfmt whose name starts with the byte 0x01 was read as a name_extracted key list and indexed an empty slice; a name holding 0x00 was split into two keys. Such names are now translated as plain names. The request path already rejects these queries with Loki's parse error, so only direct translator callers were affected. --- CHANGELOG.md | 4 ++++ internal/translator/parsed_key_variants.go | 4 +++- internal/translator/parsed_key_variants_test.go | 16 ++++++++++++++++ internal/translator/translator.go | 2 +- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec44a0859..014d1a820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- The query translator no longer panics on a label filter after `| json` or `| logfmt` whose label name contains the byte `\x01` (found by fuzzing). The proxy already rejects such a query with Loki's parse error before it reaches the translator, so clients were not affected; translator callers that skip that check now get a plain filter instead of a crash (#TBD). + ## [2.15.0] - 2026-10-12 ### Fixed diff --git a/internal/translator/parsed_key_variants.go b/internal/translator/parsed_key_variants.go index 96a517d7e..420938cc9 100644 --- a/internal/translator/parsed_key_variants.go +++ b/internal/translator/parsed_key_variants.go @@ -193,8 +193,10 @@ func withParsedKeyVariants(labelFn LabelTranslateFunc, exclude func(string) bool } // A label the translation maps (a known or learned VictoriaLogs field) // names that field; only an unmapped label can be a sanitized key. + // A name holding the bytes that separate and mark the candidate keys + // cannot be encoded as a key list (and is no key a parser produces). if translated != label || strings.HasPrefix(label, "_") || !strings.Contains(label, "_") || - strings.ContainsAny(label, ".-") || exclude(label) { + strings.ContainsAny(label, ".-"+parsedKeySep+extractedMarker) || exclude(label) { return translated } keys := parsedKeyVariants(label) diff --git a/internal/translator/parsed_key_variants_test.go b/internal/translator/parsed_key_variants_test.go index d4de80514..9dfe6f557 100644 --- a/internal/translator/parsed_key_variants_test.go +++ b/internal/translator/parsed_key_variants_test.go @@ -272,3 +272,19 @@ func TestParsedKeyVariantsAreBounded(t *testing.T) { t.Errorf("plain: %v", got) } } + +// A label name holding the bytes that separate and mark the candidate keys is +// translated as a plain name; it used to be split as a key list and panic. +func TestParsedKeyFilterNameWithSeparatorBytes(t *testing.T) { + streamFields := map[string]bool{"app": true} + for _, name := range []string{"\x01a_b", "\x01a_extracted", "\x01\x01a_b", "a_\x00b"} { + query := `{app="x"} | json | ` + name + `="v"` + got, err := TranslateLogQLWithStreamFields(query, nil, streamFields) + if err != nil { + continue + } + if !strings.Contains(got, "filter "+name+`:="v"`) { + t.Errorf("%q translated to %q", query, got) + } + } +} diff --git a/internal/translator/translator.go b/internal/translator/translator.go index 1bbf5ae8a..b69ac9f2c 100644 --- a/internal/translator/translator.go +++ b/internal/translator/translator.go @@ -1394,7 +1394,7 @@ func translateSingleLabelFilter(stage string, labelFn LabelTranslateFunc, caps l } if labelFn != nil { translated := labelFn(label) - if strings.Contains(translated, parsedKeySep) { + if strings.Contains(translated, parsedKeySep) && !strings.Contains(label, parsedKeySep) { return translateParsedKeyFilter(stage, strings.Split(translated, parsedKeySep), value, entry.entry, caps) } label = sanitizeFieldIdentifier(translated) From c94b583260d1f17176e6ec09a89823f23159c3ce Mon Sep 17 00:00:00 2001 From: szibis Date: Wed, 14 Oct 2026 17:29:58 +0200 Subject: [PATCH 2/2] docs: reference #761 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 014d1a820..dc0f72a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- The query translator no longer panics on a label filter after `| json` or `| logfmt` whose label name contains the byte `\x01` (found by fuzzing). The proxy already rejects such a query with Loki's parse error before it reaches the translator, so clients were not affected; translator callers that skip that check now get a plain filter instead of a crash (#TBD). +- The query translator no longer panics on a label filter after `| json` or `| logfmt` whose label name contains the byte `\x01` (found by fuzzing). The proxy already rejects such a query with Loki's parse error before it reaches the translator, so clients were not affected; translator callers that skip that check now get a plain filter instead of a crash (#761). ## [2.15.0] - 2026-10-12