VYPR
Critical severity9.8NVD Advisory· Published Mar 27, 2026· Updated Apr 1, 2026

CVE-2026-33701

CVE-2026-33701

Description

OpenTelemetry Java Instrumentation provides OpenTelemetry auto-instrumentation and instrumentation libraries for Java. In versions prior to 2.26.1, the RMI instrumentation registered a custom endpoint that deserialized incoming data without applying serialization filters. On JDK version 16 and earlier, an attacker with network access to a JMX or RMI port on an instrumented JVM could exploit this to potentially achieve remote code execution. All three of the following conditions must be true to exploit this vulnerability: First, OpenTelemetry Java instrumentation is attached as a Java agent (-javaagent) on Java 16 or earlier. Second, JMX/RMI port has been explicitly configured via -Dcom.sun.management.jmxremote.port and is network-reachable. Third, gadget-chain-compatible library is present on the classpath. This results in arbitrary remote code execution with the privileges of the user running the instrumented JVM. For JDK >= 17, no action is required, but upgrading is strongly encouraged. For JDK < 17, upgrade to version 2.26.1 or later. As a workaround, set the system property -Dotel.instrumentation.rmi.enabled=false to disable the RMI integration.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
io.opentelemetry.javaagent:opentelemetry-javaagentMaven
< 2.26.12.26.1

Affected products

1

Patches

1
9cf4fbaaa9e7

Fix RMI context propagation (#16979)

11 files changed · +53 28
  • CHANGELOG.md+7 0 modified
    @@ -1,5 +1,12 @@
     # Changelog
     
    +## Version 2.26.1 (2026-03-23)
    +
    +### 🛠️ Bug fixes
    +
    +- Fix RMI context propagation
    +  ([#16979](https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/16979))
    +
     ## Version 2.26.0 (2026-03-13)
     
     ### ⚠️ Breaking changes to non-stable APIs
    
  • docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-annotations.txt+1 1 modified
    @@ -1,2 +1,2 @@
    -Comparing source compatibility of opentelemetry-instrumentation-annotations-2.26.0.jar against opentelemetry-instrumentation-annotations-2.25.0.jar
    +Comparing source compatibility of opentelemetry-instrumentation-annotations-2.26.1.jar against opentelemetry-instrumentation-annotations-2.25.0.jar
     No changes.
    \ No newline at end of file
    
  • docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt+1 1 modified
    @@ -1,2 +1,2 @@
    -Comparing source compatibility of opentelemetry-instrumentation-api-2.26.0.jar against opentelemetry-instrumentation-api-2.25.0.jar
    +Comparing source compatibility of opentelemetry-instrumentation-api-2.26.1.jar against opentelemetry-instrumentation-api-2.25.0.jar
     No changes.
    \ No newline at end of file
    
  • docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-autoconfigure.txt+1 1 modified
    @@ -1,2 +1,2 @@
    -Comparing source compatibility of opentelemetry-spring-boot-autoconfigure-2.26.0.jar against opentelemetry-spring-boot-autoconfigure-2.25.0.jar
    +Comparing source compatibility of opentelemetry-spring-boot-autoconfigure-2.26.1.jar against opentelemetry-spring-boot-autoconfigure-2.25.0.jar
     No changes.
    \ No newline at end of file
    
  • docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-starter.txt+1 1 modified
    @@ -1,2 +1,2 @@
    -Comparing source compatibility of opentelemetry-spring-boot-starter-2.26.0.jar against opentelemetry-spring-boot-starter-2.25.0.jar
    +Comparing source compatibility of opentelemetry-spring-boot-starter-2.26.1.jar against opentelemetry-spring-boot-starter-2.25.0.jar
     No changes.
    \ No newline at end of file
    
  • examples/distro/build.gradle+3 3 modified
    @@ -14,7 +14,7 @@ buildscript {
       dependencies {
         classpath "com.diffplug.spotless:spotless-plugin-gradle:8.3.0"
         classpath "com.gradleup.shadow:shadow-gradle-plugin:9.3.2"
    -    classpath "io.opentelemetry.instrumentation:gradle-plugins:2.26.0-alpha"
    +    classpath "io.opentelemetry.instrumentation:gradle-plugins:2.26.1-alpha"
       }
     }
     
    @@ -30,8 +30,8 @@ subprojects {
           opentelemetrySdk           : "1.60.1",
     
           // these lines are managed by .github/scripts/update-version.sh
    -      opentelemetryJavaagent     : "2.26.0",
    -      opentelemetryJavaagentAlpha: "2.26.0-alpha",
    +      opentelemetryJavaagent     : "2.26.1",
    +      opentelemetryJavaagentAlpha: "2.26.1-alpha",
     
           autoservice                : "1.1.1"
         ]
    
  • examples/extension/build.gradle+4 4 modified
    @@ -13,8 +13,8 @@ plugins {
       id "com.gradleup.shadow" version "9.3.2"
       id "com.diffplug.spotless" version "8.3.0"
     
    -  id "io.opentelemetry.instrumentation.muzzle-generation" version "2.26.0-alpha"
    -  id "io.opentelemetry.instrumentation.muzzle-check" version "2.26.0-alpha"
    +  id "io.opentelemetry.instrumentation.muzzle-generation" version "2.26.1-alpha"
    +  id "io.opentelemetry.instrumentation.muzzle-check" version "2.26.1-alpha"
     }
     
     group 'io.opentelemetry.example'
    @@ -26,8 +26,8 @@ ext {
         opentelemetrySdk           : "1.60.1",
     
         // these lines are managed by .github/scripts/update-version.sh
    -    opentelemetryJavaagent     : "2.26.0",
    -    opentelemetryJavaagentAlpha: "2.26.0-alpha"
    +    opentelemetryJavaagent     : "2.26.1",
    +    opentelemetryJavaagentAlpha: "2.26.1-alpha"
       ]
     
       deps = [
    
  • instrumentation/rmi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rmi/context/ContextPayload.java+31 13 modified
    @@ -17,11 +17,13 @@
     import java.util.HashMap;
     import java.util.Map;
     import java.util.logging.Logger;
    +import javax.annotation.Nullable;
     
     /** ContextPayload wraps context information shared between client and server. */
     public class ContextPayload {
     
       private static final Logger logger = Logger.getLogger(ContextPayload.class.getName());
    +  private static final int MAX_CONTEXT_ENTRIES = 1000;
     
       private final Map<String, String> context;
     
    @@ -41,24 +43,40 @@ public static ContextPayload from(Context context) {
         return payload;
       }
     
    -  @SuppressWarnings("BanSerializableRead") // fine
    +  @Nullable
       public static ContextPayload read(ObjectInput oi) throws IOException {
    -    try {
    -      Object object = oi.readObject();
    -      if (object instanceof Map) {
    -        @SuppressWarnings("unchecked") // convert it back to the expected type
    -        Map<String, String> map = (Map<String, String>) object;
    -        return new ContextPayload(map);
    -      }
    -    } catch (ClassCastException | ClassNotFoundException ex) {
    -      logger.log(FINE, "Error reading object", ex);
    +    int size = oi.readInt();
    +    if (size > MAX_CONTEXT_ENTRIES) {
    +      logger.log(
    +          FINE,
    +          "RMI context propagation payload size {0} exceeds maximum allowed of {1}, skipping context propagation.",
    +          new Object[] {size, MAX_CONTEXT_ENTRIES});
    +      return null;
         }
    -
    -    return null;
    +    Map<String, String> map = new HashMap<>();
    +    for (int i = 0; i < size; i++) {
    +      String key = oi.readUTF();
    +      String value = oi.readUTF();
    +      map.put(key, value);
    +    }
    +    return new ContextPayload(map);
       }
     
       public void write(ObjectOutput out) throws IOException {
    -    out.writeObject(context);
    +    int size = context.size();
    +    if (size > MAX_CONTEXT_ENTRIES) {
    +      logger.log(
    +          FINE,
    +          "RMI context propagation payload size {0} exceeds maximum allowed of {1}, skipping context propagation.",
    +          new Object[] {size, MAX_CONTEXT_ENTRIES});
    +      out.writeInt(0);
    +      return;
    +    }
    +    out.writeInt(size);
    +    for (Map.Entry<String, String> entry : context.entrySet()) {
    +      out.writeUTF(entry.getKey());
    +      out.writeUTF(entry.getValue());
    +    }
       }
     
       public Context extract() {
    
  • instrumentation/rmi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/rmi/context/ContextPropagator.java+1 1 modified
    @@ -32,7 +32,7 @@ public class ContextPropagator {
     
       // RMI object id used to identify agent instrumentation
       public static final ObjID CONTEXT_CALL_ID =
    -      new ObjID("io.opentelemetry.javaagent.context-call".hashCode());
    +      new ObjID("io.opentelemetry.javaagent.context-call-v2".hashCode());
     
       // Operation id used for checking context propagation is possible
       // RMI expects these operations to have negative identifier, as positive ones mean legacy
    
  • README.md+1 1 modified
    @@ -33,7 +33,7 @@ If you are looking for documentation on using those.
     ## Getting Started
     
     Download
    -the [latest version](https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.26.0/opentelemetry-javaagent.jar).
    +the [latest version](https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.26.1/opentelemetry-javaagent.jar).
     
     This package includes the instrumentation agent as well as
     instrumentations for all supported libraries and all available data exporters.
    
  • version.gradle.kts+2 2 modified
    @@ -1,5 +1,5 @@
    -val stableVersion = "2.26.0"
    -val alphaVersion = "2.26.0-alpha"
    +val stableVersion = "2.26.1"
    +val alphaVersion = "2.26.1-alpha"
     
     allprojects {
       if (findProperty("otel.stable") != "true") {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.