Description
go.opentelemetry.io/otel/attribute can treat a non-empty attribute set as empty when its computed 64-bit FNV-1a hash is zero. The Set/Distinct implementation reserves hash == 0 as an invalid sentinel, but hashKVs can legitimately return zero and newSet stores that value without remapping it.
When a non-empty set has hash == 0, methods such as Len, Get, and Value return empty results, and Equivalent collapses it to the empty set. This can cause telemetry using crafted attributes to lose labels or merge into the empty label set.
Steps To Reproduce
func TestZeroHashNonEmptySetShouldNotCollapse(t *testing.T) {
kvs := []KeyValue{String("attacker", "controlled")}
s := Set{
hash: 0,
data: computeDataFixed(kvs),
}
if got := s.Len(); got != 1 {
t.Errorf("Len() = %d, want 1 for non-empty data", got)
}
if _, ok := s.Value("attacker"); !ok {
t.Errorf("Value() omitted attacker-controlled attribute")
}
if s.Equivalent() == (Distinct{hash: emptySet.hash}) {
t.Errorf("Equivalent() collapsed non-empty zero-hash set to emptySet")
}
}
Expected behavior
Attribute-set hashing should never allow a non-empty set to be represented with the reserved empty/invalid sentinel. If hashKVs returns zero, the set implementation should remap it to a non-zero value or track validity separately so Len, Get, Value, and Equivalent preserve the non-empty attributes.
Description
go.opentelemetry.io/otel/attributecan treat a non-empty attribute set as empty when its computed 64-bit FNV-1a hash is zero. TheSet/Distinctimplementation reserveshash == 0as an invalid sentinel, buthashKVscan legitimately return zero andnewSetstores that value without remapping it.When a non-empty set has
hash == 0, methods such asLen,Get, andValuereturn empty results, andEquivalentcollapses it to the empty set. This can cause telemetry using crafted attributes to lose labels or merge into the empty label set.Steps To Reproduce
Expected behavior
Attribute-set hashing should never allow a non-empty set to be represented with the reserved empty/invalid sentinel. If
hashKVsreturns zero, the set implementation should remap it to a non-zero value or track validity separately soLen,Get,Value, andEquivalentpreserve the non-empty attributes.