VYPR
Medium severity5.3GHSA Advisory· Published May 14, 2026· Updated May 14, 2026

OpenTelemetry Java SDK has Unbounded Memory Allocation in W3C Baggage Propagation

CVE-2026-45292

Description

Overview

A vulnerability affects the baggage propagation implementation in opentelemetry-api and opentelemetry-extension-trace-propagators. Parsing oversized baggage causes unbounded memory allocation and CPU consumption. Because baggage is automatically re-injected into every outgoing request, the effect can fan out to downstream services that never received the original malicious request.

Technical

Details

- W3CBaggagePropagator did not enforce any limit on the total size or entry count of the baggage header. The parser iterated character-by-character through the entire value regardless of length. - JaegerPropagator and OtTracePropagator had the same gap in their respective baggage extraction paths. - The W3C Baggage specification recommends a maximum of 8,192 bytes and 180 entries; none of these limits were enforced.

Impact

The practical availability impact for most deployments is limited. Every major Java HTTP server enforces its own header size limit (Tomcat, Jetty, Netty, Vert.x, and gRPC-Java all default to 8 KiB), constraining what an external attacker can deliver before the application is reached. The risk is higher when transport-layer limits are absent — e.g., a compromised internal service communicating over a non-HTTP or custom transport.

Remediation

Update to version 1.62.0 or later (#8380). The fix enforces limits consistent with the W3C Baggage specification at the propagator level:

  • Maximum total baggage size: 8,192 bytes across all baggage header values
  • Maximum number of entries: 64

Headers that would exceed either limit are dropped at the point the limit is reached; already-extracted valid entries are retained.

Workarounds

Ensure HTTP header size limits are configured at the server or gateway level. Most Java HTTP servers enforce an 8 KiB header limit by default, which mitigates external attack vectors independently of this fix.

References

Affected products

1

Patches

1
03837d3c1763

Apply baggage limits (#8380)

7 files changed · +427 21
  • api/all/src/main/java/io/opentelemetry/api/baggage/propagation/Parser.java+14 3 modified
    @@ -27,6 +27,7 @@ private enum State {
       }
     
       private final String baggageHeader;
    +  private final int maxEntries;
     
       private final Element key = Element.createKeyElement();
       private final Element value = Element.createValueElement();
    @@ -36,14 +37,19 @@ private enum State {
       private int metaStart;
     
       private boolean skipToNext;
    +  private int entriesAdded;
     
    -  Parser(String baggageHeader) {
    +  Parser(String baggageHeader, int maxEntries) {
         this.baggageHeader = baggageHeader;
    +    this.maxEntries = maxEntries;
         reset(0);
       }
     
    -  void parseInto(BaggageBuilder baggageBuilder) {
    +  int parseInto(BaggageBuilder baggageBuilder) {
         for (int i = 0, n = baggageHeader.length(); i < n; i++) {
    +      if (entriesAdded >= maxEntries) {
    +        break;
    +      }
           char current = baggageHeader.charAt(i);
     
           if (skipToNext) {
    @@ -123,13 +129,17 @@ void parseInto(BaggageBuilder baggageBuilder) {
               }
             }
         }
    +    return entriesAdded;
       }
     
    -  private static void putBaggage(
    +  private void putBaggage(
           BaggageBuilder baggage,
           @Nullable String key,
           @Nullable String value,
           @Nullable String metadataValue) {
    +    if (entriesAdded >= maxEntries) {
    +      return;
    +    }
         String decodedValue = decodeValue(value);
         metadataValue = decodeValue(metadataValue);
         BaggageEntryMetadata baggageEntryMetadata =
    @@ -138,6 +148,7 @@ private static void putBaggage(
                 : BaggageEntryMetadata.empty();
         if (key != null && decodedValue != null) {
           baggage.put(key, decodedValue, baggageEntryMetadata);
    +      entriesAdded++;
         }
       }
     
    
  • api/all/src/main/java/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.java+54 6 modified
    @@ -19,17 +19,23 @@
     import java.util.Collection;
     import java.util.Iterator;
     import java.util.List;
    +import java.util.logging.Logger;
     import javax.annotation.Nullable;
     
     /**
      * {@link TextMapPropagator} that implements the W3C specification for baggage header propagation.
      */
     public final class W3CBaggagePropagator implements TextMapPropagator {
     
    +  // Limits from https://www.w3.org/TR/baggage/#limits
    +  private static final int MAX_BAGGAGE_ENTRIES = 64;
    +  private static final int MAX_BAGGAGE_BYTES = 8192;
    +
       private static final String FIELD = "baggage";
       private static final List<String> FIELDS = singletonList(FIELD);
       private static final W3CBaggagePropagator INSTANCE = new W3CBaggagePropagator();
       private static final PercentEscaper URL_ESCAPER = PercentEscaper.create();
    +  private static final Logger LOGGER = Logger.getLogger(W3CBaggagePropagator.class.getName());
     
       /** Singleton instance of the W3C Baggage Propagator. */
       public static W3CBaggagePropagator getInstance() {
    @@ -61,17 +67,34 @@ public <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> se
     
       private static String baggageToString(Baggage baggage) {
         StringBuilder headerContent = new StringBuilder();
    +    int[] entryCount = {0};
         baggage.forEach(
             (key, baggageEntry) -> {
               if (baggageIsInvalid(key, baggageEntry)) {
                 return;
               }
    -          headerContent.append(key).append("=").append(encodeValue(baggageEntry.getValue()));
    +          if (entryCount[0] >= MAX_BAGGAGE_ENTRIES) {
    +            return;
    +          }
    +          String encodedValue = encodeValue(baggageEntry.getValue());
               String metadataValue = baggageEntry.getMetadata().getValue();
    -          if (metadataValue != null && !metadataValue.isEmpty()) {
    -            headerContent.append(";").append(encodeValue(metadataValue));
    +          String encodedMetadata =
    +              (metadataValue != null && !metadataValue.isEmpty())
    +                  ? encodeValue(metadataValue)
    +                  : null;
    +          // Exit early if adding this entry causes the total length to exceed the limit
    +          // encodedEntryLength includes a trailing comma; the final string trims exactly one,
    +          // so the net contribution to the final length is entryLength - 1.
    +          if (headerContent.length() + encodedEntryLength(key, encodedValue, encodedMetadata) - 1
    +              > MAX_BAGGAGE_BYTES) {
    +            return;
    +          }
    +          headerContent.append(key).append("=").append(encodedValue);
    +          if (encodedMetadata != null) {
    +            headerContent.append(";").append(encodedMetadata);
               }
               headerContent.append(",");
    +          entryCount[0]++;
             });
     
         if (headerContent.length() == 0) {
    @@ -87,6 +110,21 @@ private static String encodeValue(String value) {
         return URL_ESCAPER.escape(value);
       }
     
    +  /**
    +   * Returns the length of the serialized entry as it would appear in the baggage header, including
    +   * the trailing comma used by the trailing-comma pattern in {@link #baggageToString}. The length
    +   * accounts for {@code "key=encodedValue,"} plus {@code ";encodedMetadata"} when metadata is
    +   * present.
    +   */
    +  private static int encodedEntryLength(
    +      String key, String encodedValue, @Nullable String encodedMetadata) {
    +    int length = key.length() + 1 + encodedValue.length() + 1; // "key=value,"
    +    if (encodedMetadata != null) {
    +      length += 1 + encodedMetadata.length(); // ";metadata"
    +    }
    +    return length;
    +  }
    +
       @Override
       public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {
         if (context == null) {
    @@ -108,16 +146,25 @@ private static <C> Context extractMulti(
     
         boolean extracted = false;
         BaggageBuilder baggageBuilder = Baggage.builder();
    +    int totalBytes = 0;
    +    int totalEntries = 0;
     
         while (baggageHeaders.hasNext()) {
           String header = baggageHeaders.next();
           if (header.isEmpty()) {
             continue;
           }
     
    +      totalBytes += header.length();
    +      if (totalBytes > MAX_BAGGAGE_BYTES || totalEntries >= MAX_BAGGAGE_ENTRIES) {
    +        LOGGER.fine("Baggage header exceeded W3C limits, dropping remaining entries");
    +        break;
    +      }
    +
           try {
    -        extractEntries(header, baggageBuilder);
    +        int added = extractEntries(header, baggageBuilder, MAX_BAGGAGE_ENTRIES - totalEntries);
             extracted = true;
    +        totalEntries += added;
           } catch (RuntimeException expected) {
             // invalid baggage header, continue
           }
    @@ -126,8 +173,9 @@ private static <C> Context extractMulti(
         return extracted ? context.with(baggageBuilder.build()) : context;
       }
     
    -  private static void extractEntries(String baggageHeader, BaggageBuilder baggageBuilder) {
    -    new Parser(baggageHeader).parseInto(baggageBuilder);
    +  private static int extractEntries(
    +      String baggageHeader, BaggageBuilder baggageBuilder, int maxEntries) {
    +    return new Parser(baggageHeader, maxEntries).parseInto(baggageBuilder);
       }
     
       private static boolean baggageIsInvalid(String key, BaggageEntry baggageEntry) {
    
  • api/all/src/test/java/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagatorTest.java+114 0 modified
    @@ -11,17 +11,23 @@
     import com.google.common.collect.ImmutableList;
     import com.google.common.collect.ImmutableMap;
     import io.opentelemetry.api.baggage.Baggage;
    +import io.opentelemetry.api.baggage.BaggageBuilder;
     import io.opentelemetry.api.baggage.BaggageEntryMetadata;
     import io.opentelemetry.context.Context;
     import io.opentelemetry.context.propagation.TextMapGetter;
    +import java.util.Arrays;
     import java.util.Collections;
     import java.util.HashMap;
     import java.util.Iterator;
     import java.util.LinkedHashMap;
     import java.util.List;
     import java.util.Map;
    +import java.util.stream.Stream;
     import javax.annotation.Nullable;
     import org.junit.jupiter.api.Test;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.Arguments;
    +import org.junit.jupiter.params.provider.MethodSource;
     
     class W3CBaggagePropagatorTest {
     
    @@ -595,6 +601,114 @@ void inject_nullSetter() {
         assertThat(carrier).isEmpty();
       }
     
    +  @ParameterizedTest
    +  @MethodSource
    +  void extract_limit_maxEntries(List<String> headers, Baggage expectedBaggage) {
    +    Context result =
    +        W3CBaggagePropagator.getInstance()
    +            .extract(Context.root(), ImmutableMap.of("baggage", headers), multiGetter);
    +    assertThat(Baggage.fromContext(result)).isEqualTo(expectedBaggage);
    +  }
    +
    +  static Stream<Arguments> extract_limit_maxEntries() {
    +    return Stream.of(
    +        // Exactly at the limit — all 64 entries extracted
    +        Arguments.of(ImmutableList.of(baggageHeader(0, 64)), baggageWithEntries(0, 64)),
    +        // One over the limit — only the first 64 extracted
    +        Arguments.of(ImmutableList.of(baggageHeader(0, 65)), baggageWithEntries(0, 64)),
    +        // Split across two headers — only the first 64 total extracted
    +        Arguments.of(
    +            ImmutableList.of(baggageHeader(0, 32), baggageHeader(32, 33)),
    +            baggageWithEntries(0, 64)));
    +  }
    +
    +  /**
    +   * Builds a {@link Baggage} with entries {@code k{start}=v{start}} through {@code
    +   * k{start+count-1}=v{start+count-1}}.
    +   */
    +  private static Baggage baggageWithEntries(int start, int count) {
    +    BaggageBuilder builder = Baggage.builder();
    +    for (int i = start; i < start + count; i++) {
    +      builder.put("k" + i, "v" + i);
    +    }
    +    return builder.build();
    +  }
    +
    +  /** Builds {@code "k{start}=v{start},...,k{start+count-1}=v{start+count-1}"}. */
    +  private static String baggageHeader(int start, int count) {
    +    StringBuilder sb = new StringBuilder();
    +    for (int i = start; i < start + count; i++) {
    +      if (i > start) {
    +        sb.append(",");
    +      }
    +      sb.append("k").append(i).append("=v").append(i);
    +    }
    +    return sb.toString();
    +  }
    +
    +  @Test
    +  void extract_limit_maxBytes_exceedsLimit() {
    +    W3CBaggagePropagator propagator = W3CBaggagePropagator.getInstance();
    +    // Single header over 8192 bytes — dropped entirely; partial values must not be extracted
    +    String header = "k=" + fillChars('v', 8192); // 8194 bytes
    +    Context result = propagator.extract(Context.root(), ImmutableMap.of("baggage", header), getter);
    +    assertThat(Baggage.fromContext(result)).isEqualTo(Baggage.empty());
    +  }
    +
    +  @Test
    +  void extract_limit_maxBytes_acrossMultipleHeaders() {
    +    W3CBaggagePropagator propagator = W3CBaggagePropagator.getInstance();
    +    // First header just under 8192 bytes is extracted; second header pushes total over the limit
    +    String almostMax = "k=" + fillChars('v', 8189); // "k=vvv..."
    +    String second = "k2=v2";
    +    Context result =
    +        propagator.extract(
    +            Context.root(),
    +            ImmutableMap.of("baggage", ImmutableList.of(almostMax, second)),
    +            multiGetter);
    +    // Only the first header should have been extracted
    +    assertThat(Baggage.fromContext(result).size()).isEqualTo(1);
    +    assertThat(Baggage.fromContext(result).getEntryValue("k2")).isNull();
    +  }
    +
    +  @Test
    +  void inject_limit_maxEntries() {
    +    Map<String, String> carrier = new HashMap<>();
    +    W3CBaggagePropagator.getInstance()
    +        .inject(Context.root().with(baggageWithEntries(0, 74)), carrier, Map::put);
    +    String header = carrier.get("baggage");
    +    assertThat(header).isNotNull();
    +    long count = header.chars().filter(c -> c == '=').count();
    +    assertThat(count).isEqualTo(64);
    +  }
    +
    +  @Test
    +  void inject_limit_maxBytes() {
    +    W3CBaggagePropagator propagator = W3CBaggagePropagator.getInstance();
    +    // One entry whose encoded form alone exceeds the byte limit — should produce empty header
    +    Baggage baggage = Baggage.builder().put("k", fillChars('v', 8192)).build();
    +    Map<String, String> carrier = new HashMap<>();
    +    propagator.inject(Context.root().with(baggage), carrier, Map::put);
    +    assertThat(carrier).doesNotContainKey("baggage");
    +  }
    +
    +  @Test
    +  void inject_limit_maxBytes_metadata() {
    +    // Value alone fits easily (k=v is 3 bytes), but k=v;{metadata} exceeds 8192 bytes.
    +    // Verifies that metadata length is included in the byte limit check.
    +    Baggage baggage =
    +        Baggage.builder().put("k", "v", BaggageEntryMetadata.create(fillChars('x', 8190))).build();
    +    Map<String, String> carrier = new HashMap<>();
    +    W3CBaggagePropagator.getInstance().inject(Context.root().with(baggage), carrier, Map::put);
    +    assertThat(carrier).doesNotContainKey("baggage");
    +  }
    +
    +  private static String fillChars(char c, int count) {
    +    char[] chars = new char[count];
    +    Arrays.fill(chars, c);
    +    return new String(chars);
    +  }
    +
       @Test
       void toString_Valid() {
         assertThat(W3CBaggagePropagator.getInstance().toString()).isEqualTo("W3CBaggagePropagator");
    
  • extensions/trace-propagators/src/main/java/io/opentelemetry/extension/trace/propagation/JaegerPropagator.java+56 10 modified
    @@ -72,6 +72,11 @@ public final class JaegerPropagator implements TextMapPropagator {
           PARENT_SPAN_ID_OFFSET + PARENT_SPAN_ID_SIZE + PROPAGATION_HEADER_DELIMITER_SIZE;
       private static final int PROPAGATION_HEADER_SIZE = SAMPLED_FLAG_OFFSET + SAMPLED_FLAG_SIZE;
     
    +  // No limits are defined by the Jaeger format; borrow the W3C Baggage spec limits as a
    +  // defense-in-depth measure (https://www.w3.org/TR/baggage/#limits).
    +  private static final int MAX_BAGGAGE_ENTRIES = 64;
    +  private static final int MAX_BAGGAGE_BYTES = 8192;
    +
       private static final Collection<String> FIELDS = Collections.singletonList(PROPAGATION_HEADER);
       private static final JaegerPropagator INSTANCE = new JaegerPropagator();
     
    @@ -126,8 +131,21 @@ private static <C> void injectSpan(
     
       private static <C> void injectBaggage(
           Baggage baggage, @Nullable C carrier, TextMapSetter<C> setter) {
    +    int[] entriesEmitted = {0};
    +    int[] bytesEmitted = {0};
         baggage.forEach(
    -        (key, baggageEntry) -> setter.set(carrier, BAGGAGE_PREFIX + key, baggageEntry.getValue()));
    +        (key, baggageEntry) -> {
    +          if (entriesEmitted[0] >= MAX_BAGGAGE_ENTRIES) {
    +            return;
    +          }
    +          String value = baggageEntry.getValue();
    +          if (bytesEmitted[0] + key.length() + value.length() > MAX_BAGGAGE_BYTES) {
    +            return;
    +          }
    +          setter.set(carrier, BAGGAGE_PREFIX + key, value);
    +          entriesEmitted[0]++;
    +          bytesEmitted[0] += key.length() + value.length();
    +        });
       }
     
       @Override
    @@ -228,46 +246,74 @@ private static <C> SpanContext getSpanContextFromHeader(
       @Nullable
       private static <C> Baggage getBaggageFromHeader(@Nullable C carrier, TextMapGetter<C> getter) {
         BaggageBuilder builder = null;
    +    int entriesAdded = 0;
    +    int bytesAdded = 0;
     
         Iterable<String> keys = carrier != null ? getter.keys(carrier) : Collections.emptyList();
     
         for (String key : keys) {
    +      if (entriesAdded >= MAX_BAGGAGE_ENTRIES || bytesAdded > MAX_BAGGAGE_BYTES) {
    +        break;
    +      }
           if (key.startsWith(BAGGAGE_PREFIX)) {
             if (key.length() == BAGGAGE_PREFIX.length()) {
               continue;
             }
    -
    -        if (builder == null) {
    -          builder = Baggage.builder();
    -        }
    -
             String value = getter.get(carrier, key);
             if (value != null) {
    -          builder.put(key.substring(BAGGAGE_PREFIX.length()), value);
    +          String baggageKey = key.substring(BAGGAGE_PREFIX.length());
    +          if (bytesAdded + baggageKey.length() + value.length() > MAX_BAGGAGE_BYTES) {
    +            break;
    +          }
    +          if (builder == null) {
    +            builder = Baggage.builder();
    +          }
    +          builder.put(baggageKey, value);
    +          entriesAdded++;
    +          bytesAdded += baggageKey.length() + value.length();
             }
           } else if (key.equals(BAGGAGE_HEADER)) {
             String value = getter.get(carrier, key);
             if (value != null) {
               if (builder == null) {
                 builder = Baggage.builder();
               }
    -          builder = parseBaggageHeader(value, builder);
    +          int[] counts =
    +              parseBaggageHeader(
    +                  value,
    +                  builder,
    +                  MAX_BAGGAGE_ENTRIES - entriesAdded,
    +                  MAX_BAGGAGE_BYTES - bytesAdded);
    +          entriesAdded += counts[0];
    +          bytesAdded += counts[1];
             }
           }
         }
         return builder == null ? null : builder.build();
       }
     
    -  private static BaggageBuilder parseBaggageHeader(String header, BaggageBuilder builder) {
    +  /** Returns a two-element array of {@code [entriesAdded, bytesAdded]}. */
    +  private static int[] parseBaggageHeader(
    +      String header, BaggageBuilder builder, int maxEntries, int maxBytes) {
    +    int entriesAdded = 0;
    +    int bytesAdded = 0;
         for (String part : header.split("\\s*,\\s*")) {
    +      if (entriesAdded >= maxEntries || bytesAdded > maxBytes) {
    +        break;
    +      }
           String[] kv = part.split("\\s*=\\s*");
           if (kv.length == 2) {
    +        if (bytesAdded + kv[0].length() + kv[1].length() > maxBytes) {
    +          break;
    +        }
             builder.put(kv[0], kv[1]);
    +        entriesAdded++;
    +        bytesAdded += kv[0].length() + kv[1].length();
           } else {
             logger.fine("malformed token in " + BAGGAGE_HEADER + " header: " + part);
           }
         }
    -    return builder;
    +    return new int[] {entriesAdded, bytesAdded};
       }
     
       private static SpanContext buildSpanContext(String traceId, String spanId, String flags) {
    
  • extensions/trace-propagators/src/main/java/io/opentelemetry/extension/trace/propagation/OtTracePropagator.java+29 2 modified
    @@ -50,6 +50,11 @@ public final class OtTracePropagator implements TextMapPropagator {
       private static final Collection<String> FIELDS =
           Collections.unmodifiableList(Arrays.asList(TRACE_ID_HEADER, SPAN_ID_HEADER, SAMPLED_HEADER));
     
    +  // No limits are defined by the OT trace format; borrow the W3C Baggage spec limits as a
    +  // defense-in-depth measure (https://www.w3.org/TR/baggage/#limits).
    +  private static final int MAX_BAGGAGE_ENTRIES = 64;
    +  private static final int MAX_BAGGAGE_BYTES = 8192;
    +
       private static final OtTracePropagator INSTANCE = new OtTracePropagator();
     
       private OtTracePropagator() {
    @@ -85,9 +90,21 @@ public <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> se
         Baggage baggage = Baggage.fromContext(context);
         if (!baggage.isEmpty()) {
           // Metadata is not supported by OpenTracing
    +      int[] entriesEmitted = {0};
    +      int[] bytesEmitted = {0};
           baggage.forEach(
    -          (key, baggageEntry) ->
    -              setter.set(carrier, PREFIX_BAGGAGE_HEADER + key, baggageEntry.getValue()));
    +          (key, baggageEntry) -> {
    +            if (entriesEmitted[0] >= MAX_BAGGAGE_ENTRIES) {
    +              return;
    +            }
    +            String value = baggageEntry.getValue();
    +            if (bytesEmitted[0] + key.length() + value.length() > MAX_BAGGAGE_BYTES) {
    +              return;
    +            }
    +            setter.set(carrier, PREFIX_BAGGAGE_HEADER + key, value);
    +            entriesEmitted[0]++;
    +            bytesEmitted[0] += key.length() + value.length();
    +          });
         }
       }
     
    @@ -122,7 +139,12 @@ public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C
         // Baggage is only extracted if there is a valid SpanContext
         if (carrier != null) {
           BaggageBuilder baggageBuilder = Baggage.builder();
    +      int entriesAdded = 0;
    +      int bytesAdded = 0;
           for (String key : getter.keys(carrier)) {
    +        if (entriesAdded >= MAX_BAGGAGE_ENTRIES || bytesAdded > MAX_BAGGAGE_BYTES) {
    +          break;
    +        }
             String lowercaseKey = key.toLowerCase(Locale.ROOT);
             if (!lowercaseKey.startsWith(PREFIX_BAGGAGE_HEADER)) {
               continue;
    @@ -133,7 +155,12 @@ public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C
             }
             String baggageKey =
                 lowercaseKey.substring(OtTracePropagator.PREFIX_BAGGAGE_HEADER.length());
    +        if (bytesAdded + baggageKey.length() + value.length() > MAX_BAGGAGE_BYTES) {
    +          break;
    +        }
             baggageBuilder.put(baggageKey, value);
    +        entriesAdded++;
    +        bytesAdded += baggageKey.length() + value.length();
           }
           Baggage baggage = baggageBuilder.build();
           if (!baggage.isEmpty()) {
    
  • extensions/trace-propagators/src/test/java/io/opentelemetry/extension/trace/propagation/JaegerPropagatorTest.java+73 0 modified
    @@ -12,6 +12,7 @@
     import io.jaegertracing.internal.JaegerSpanContext;
     import io.jaegertracing.internal.propagation.TextMapCodec;
     import io.opentelemetry.api.baggage.Baggage;
    +import io.opentelemetry.api.baggage.BaggageBuilder;
     import io.opentelemetry.api.baggage.BaggageEntryMetadata;
     import io.opentelemetry.api.trace.Span;
     import io.opentelemetry.api.trace.SpanContext;
    @@ -25,11 +26,16 @@
     import java.io.UnsupportedEncodingException;
     import java.net.URLEncoder;
     import java.nio.charset.StandardCharsets;
    +import java.util.Arrays;
     import java.util.Collections;
     import java.util.LinkedHashMap;
     import java.util.Map;
    +import java.util.stream.Stream;
     import javax.annotation.Nullable;
     import org.junit.jupiter.api.Test;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.Arguments;
    +import org.junit.jupiter.params.provider.MethodSource;
     
     /** Unit tests for {@link JaegerPropagator}. */
     @SuppressWarnings("deprecation")
    @@ -466,6 +472,73 @@ void extract_nullGetter() {
         assertThat(jaegerPropagator.extract(context, Collections.emptyMap(), null)).isSameAs(context);
       }
     
    +  @Test
    +  void inject_baggageLimit_maxEntries() {
    +    Map<String, String> carrier = new LinkedHashMap<>();
    +    jaegerPropagator.inject(Context.root().with(baggageWithEntries(0, 65)), carrier, Map::put);
    +    long count = carrier.keySet().stream().filter(k -> k.startsWith(BAGGAGE_PREFIX)).count();
    +    assertThat(count).isEqualTo(64);
    +  }
    +
    +  @Test
    +  void inject_baggageLimit_maxBytes() {
    +    Baggage baggage = Baggage.builder().put("k", fillChars('v', 8192)).build();
    +    Map<String, String> carrier = new LinkedHashMap<>();
    +    jaegerPropagator.inject(Context.root().with(baggage), carrier, Map::put);
    +    assertThat(carrier).doesNotContainKey(BAGGAGE_PREFIX + "k");
    +  }
    +
    +  @ParameterizedTest
    +  @MethodSource
    +  void extract_baggageLimit(Map<String, String> carrier, Baggage expectedBaggage) {
    +    assertThat(fromContext(jaegerPropagator.extract(Context.root(), carrier, getter)))
    +        .isEqualTo(expectedBaggage);
    +  }
    +
    +  static Stream<Arguments> extract_baggageLimit() {
    +    Map<String, String> prefixCarrier = new LinkedHashMap<>();
    +    for (int i = 0; i < 65; i++) {
    +      prefixCarrier.put(BAGGAGE_PREFIX + "k" + i, "v" + i);
    +    }
    +    StringBuilder jaegerHeader = new StringBuilder();
    +    for (int i = 0; i < 65; i++) {
    +      if (i > 0) {
    +        jaegerHeader.append(",");
    +      }
    +      jaegerHeader.append("k").append(i).append("=v").append(i);
    +    }
    +    Map<String, String> headerCarrier = new LinkedHashMap<>();
    +    headerCarrier.put(BAGGAGE_HEADER, jaegerHeader.toString());
    +    Map<String, String> bigValueCarrier = new LinkedHashMap<>();
    +    bigValueCarrier.put(BAGGAGE_PREFIX + "k", fillChars('v', 8192));
    +    return Stream.of(
    +        // 65 uberctx- prefix keys — only first 64 extracted
    +        Arguments.of(prefixCarrier, baggageWithEntries(0, 64)),
    +        // 65 entries in jaeger-baggage header — only first 64 extracted
    +        Arguments.of(headerCarrier, baggageWithEntries(0, 64)),
    +        // single entry whose value exceeds the byte limit — not extracted
    +        Arguments.of(bigValueCarrier, Baggage.empty()));
    +  }
    +
    +  /**
    +   * Builds a {@link Baggage} with entries {@code k{start}=v{start}} through {@code
    +   * k{start+count-1}=v{start+count-1}}.
    +   */
    +  private static Baggage baggageWithEntries(int start, int count) {
    +    BaggageBuilder builder = Baggage.builder();
    +    for (int i = start; i < start + count; i++) {
    +      builder.put("k" + i, "v" + i);
    +    }
    +    return builder.build();
    +  }
    +
    +  /** Returns a string of {@code count} repetitions of {@code c}. */
    +  private static String fillChars(char c, int count) {
    +    char[] chars = new char[count];
    +    Arrays.fill(chars, c);
    +    return new String(chars);
    +  }
    +
       @Test
       void toString_Valid() {
         assertThat(jaegerPropagator.toString()).isEqualTo("JaegerPropagator");
    
  • extensions/trace-propagators/src/test/java/io/opentelemetry/extension/trace/propagation/OtTracePropagatorTest.java+87 0 modified
    @@ -8,6 +8,7 @@
     import static org.assertj.core.api.Assertions.assertThat;
     
     import io.opentelemetry.api.baggage.Baggage;
    +import io.opentelemetry.api.baggage.BaggageBuilder;
     import io.opentelemetry.api.trace.Span;
     import io.opentelemetry.api.trace.SpanContext;
     import io.opentelemetry.api.trace.SpanId;
    @@ -17,13 +18,18 @@
     import io.opentelemetry.context.Context;
     import io.opentelemetry.context.propagation.TextMapGetter;
     import io.opentelemetry.context.propagation.TextMapSetter;
    +import java.util.Arrays;
     import java.util.Collections;
     import java.util.HashMap;
     import java.util.LinkedHashMap;
     import java.util.Locale;
     import java.util.Map;
    +import java.util.stream.Stream;
     import javax.annotation.Nullable;
     import org.junit.jupiter.api.Test;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.Arguments;
    +import org.junit.jupiter.params.provider.MethodSource;
     
     @SuppressWarnings("deprecation")
     class OtTracePropagatorTest {
    @@ -412,6 +418,87 @@ void extract_nullGetter() {
         assertThat(propagator.extract(context, Collections.emptyMap(), null)).isSameAs(context);
       }
     
    +  @Test
    +  void inject_baggageLimit_maxEntries() {
    +    Map<String, String> carrier = new LinkedHashMap<>();
    +    propagator.inject(
    +        withSpanContext(
    +            SpanContext.create(TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault()),
    +            Context.current().with(baggageWithEntries(0, 65))),
    +        carrier,
    +        setter);
    +    long count =
    +        carrier.keySet().stream()
    +            .filter(k -> k.startsWith(OtTracePropagator.PREFIX_BAGGAGE_HEADER))
    +            .count();
    +    assertThat(count).isEqualTo(64);
    +  }
    +
    +  @Test
    +  void inject_baggageLimit_maxBytes() {
    +    Baggage baggage = Baggage.builder().put("k", fillChars('v', 8192)).build();
    +    Map<String, String> carrier = new LinkedHashMap<>();
    +    propagator.inject(
    +        withSpanContext(
    +            SpanContext.create(TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault()),
    +            Context.current().with(baggage)),
    +        carrier,
    +        setter);
    +    assertThat(carrier).doesNotContainKey(OtTracePropagator.PREFIX_BAGGAGE_HEADER + "k");
    +  }
    +
    +  @ParameterizedTest
    +  @MethodSource
    +  void extract_baggageLimit(Map<String, String> carrier, Baggage expectedBaggage) {
    +    assertThat(Baggage.fromContext(propagator.extract(Context.root(), carrier, getter)))
    +        .isEqualTo(expectedBaggage);
    +  }
    +
    +  static Stream<Arguments> extract_baggageLimit() {
    +    // Valid span context is required for baggage to be extracted
    +    Map<String, String> manyEntriesCarrier = carrierWithSpanContext();
    +    for (int i = 0; i < 65; i++) {
    +      manyEntriesCarrier.put(OtTracePropagator.PREFIX_BAGGAGE_HEADER + "k" + i, "v" + i);
    +    }
    +    Map<String, String> bigValueCarrier = carrierWithSpanContext();
    +    bigValueCarrier.put(OtTracePropagator.PREFIX_BAGGAGE_HEADER + "k", fillChars('v', 8192));
    +    return Stream.of(
    +        // 65 ot-baggage- keys — only first 64 extracted
    +        Arguments.of(manyEntriesCarrier, baggageWithEntries(0, 64)),
    +        // single entry whose value exceeds the byte limit — not extracted
    +        Arguments.of(bigValueCarrier, Baggage.empty()));
    +  }
    +
    +  /**
    +   * Returns a carrier pre-populated with a valid span context (required for baggage extraction).
    +   */
    +  private static Map<String, String> carrierWithSpanContext() {
    +    Map<String, String> carrier = new LinkedHashMap<>();
    +    carrier.put(OtTracePropagator.TRACE_ID_HEADER, TRACE_ID_RIGHT_PART);
    +    carrier.put(OtTracePropagator.SPAN_ID_HEADER, SPAN_ID);
    +    carrier.put(OtTracePropagator.SAMPLED_HEADER, "true");
    +    return carrier;
    +  }
    +
    +  /**
    +   * Builds a {@link Baggage} with entries {@code k{start}=v{start}} through {@code
    +   * k{start+count-1}=v{start+count-1}}.
    +   */
    +  private static Baggage baggageWithEntries(int start, int count) {
    +    BaggageBuilder builder = Baggage.builder();
    +    for (int i = start; i < start + count; i++) {
    +      builder.put("k" + i, "v" + i);
    +    }
    +    return builder.build();
    +  }
    +
    +  /** Returns a string of {@code count} repetitions of {@code c}. */
    +  private static String fillChars(char c, int count) {
    +    char[] chars = new char[count];
    +    Arrays.fill(chars, c);
    +    return new String(chars);
    +  }
    +
       @Test
       void toString_Valid() {
         assertThat(propagator.toString()).isEqualTo("OtTracePropagator");
    

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

5

News mentions

0

No linked articles in our index yet.