From 4693e196baa6b830a46665d437c2af283db2040b Mon Sep 17 00:00:00 2001 From: A Tobey Date: Mon, 9 Feb 2026 00:48:37 +0000 Subject: [PATCH] fix(attrs): use base-10 only for int parsing - prevent hex/octal coercion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strconv.ParseInt with base 0 auto-detects hex (0x), octal (0o), and binary (0b) prefixes, causing attribute values like "0x0" and "0xFF" to silently parse as integers instead of remaining strings. Users passing hex strings as attribute values got unexpected type coercion. Fixes #373 🤖 Claude --- otlpclient/protobuf_span.go | 5 +++-- otlpclient/protobuf_span_test.go | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/otlpclient/protobuf_span.go b/otlpclient/protobuf_span.go index 8d121a9..eaae06f 100644 --- a/otlpclient/protobuf_span.go +++ b/otlpclient/protobuf_span.go @@ -164,8 +164,9 @@ func StringMapAttrsToProtobuf(attributes map[string]string) []*commonpb.KeyValue for k, v := range attributes { av := new(commonpb.AnyValue) - // try to parse as numbers, and fall through to string - if i, err := strconv.ParseInt(v, 0, 64); err == nil { + // try to parse as decimal numbers, and fall through to string + // base 10 only: base 0 would auto-detect hex/octal prefixes (#373) + if i, err := strconv.ParseInt(v, 10, 64); err == nil { av.Value = &commonpb.AnyValue_IntValue{IntValue: i} } else if f, err := strconv.ParseFloat(v, 64); err == nil { av.Value = &commonpb.AnyValue_DoubleValue{DoubleValue: f} diff --git a/otlpclient/protobuf_span_test.go b/otlpclient/protobuf_span_test.go index b207976..87b5d43 100644 --- a/otlpclient/protobuf_span_test.go +++ b/otlpclient/protobuf_span_test.go @@ -192,6 +192,9 @@ func TestCliAttrsToOtel(t *testing.T) { "test 5 - bool, false": "false", "test 6 - bool, True": "True", "test 7 - bool, False": "False", + "test 8 - hex string": "0x0", + "test 9 - hex string2": "0xFF", + "test 10 - octal str": "0o777", } otelAttrs := StringMapAttrsToProtobuf(testAttrs) @@ -228,6 +231,21 @@ func TestCliAttrsToOtel(t *testing.T) { if attr.Value.GetBoolValue() != false { t.Errorf("expected value '%s' for key '%s' but got %t", testAttrs[key], key, attr.Value.GetBoolValue()) } + case "test 8 - hex string": + // #373: 0x0 should be treated as a string, not parsed as hex int + if attr.Value.GetStringValue() != "0x0" { + t.Errorf("expected string value '0x0' for key '%s' but got parsed as different type", key) + } + case "test 9 - hex string2": + // #373: 0xFF should be treated as a string, not parsed as hex int + if attr.Value.GetStringValue() != "0xFF" { + t.Errorf("expected string value '0xFF' for key '%s' but got parsed as different type", key) + } + case "test 10 - octal str": + // 0o777 should be treated as a string, not parsed as octal int + if attr.Value.GetStringValue() != "0o777" { + t.Errorf("expected string value '0o777' for key '%s' but got parsed as different type", key) + } } } }