From 7e3a75903159153c877daeb2952a552701e38044 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 11 Jun 2026 08:34:19 +0000
Subject: [PATCH] CVE-2026-46495 OpenDJ Unauthenticated RCE via Java Deserialization in JMX RMI

---
 opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java |   37 +++++++++++++++++++++++++++++++++++++
 1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java
index 33a9ba6..1a418b9 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/RmiConnector.java
@@ -13,6 +13,7 @@
  *
  * Copyright 2006-2009 Sun Microsystems, Inc.
  * Portions Copyright 2013-2015 ForgeRock AS.
+ * Portions Copyright 2023-2026 3A Systems, LLC.
  */
 package org.opends.server.protocols.jmx;
 
@@ -22,6 +23,7 @@
 import java.rmi.registry.LocateRegistry;
 import java.rmi.registry.Registry;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.SortedSet;
 
 import javax.net.ssl.KeyManager;
@@ -63,6 +65,29 @@
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
+  static final String JMX_REMOTE_RMI_SERVER_CREDENTIAL_TYPES =
+      "jmx.remote.rmi.server.credential.types";
+
+  /**
+   * JDK 10+ JMX environment property scoping a JEP 290 deserialization
+   * filter to the credentials object passed during {@code newClient()}.
+   * Using the credentials-scoped filter (instead of the connector-wide
+   * {@code jmx.remote.rmi.server.serial.filter.pattern}) avoids breaking
+   * legitimate JMX traffic such as MBean invocations and notifications,
+   * which may legitimately carry non-String types.
+   */
+  static final String JMX_REMOTE_RMI_SERVER_CREDENTIALS_FILTER_PATTERN =
+      "jmx.remote.rmi.server.credentials.filter.pattern";
+
+  private static final String[] JMX_CREDENTIAL_TYPES =
+  {
+    String.class.getName(),
+    String[].class.getName()
+  };
+
+  private static final String JMX_CREDENTIAL_SERIAL_FILTER =
+      "maxdepth=3;maxarray=2;java.lang.String;!*";
+
 
   /**
    * The MBean server used to handle JMX interaction.
@@ -253,6 +278,7 @@
     {
       // Environment map
       HashMap<String, Object> env = new HashMap<>();
+      configureJmxDeserializationProtection(env);
 
       // ---------------------
       // init an ssl context
@@ -364,6 +390,17 @@
 
   }
 
+  static void configureJmxDeserializationProtection(Map<String, Object> env)
+  {
+    env.put(JMX_REMOTE_RMI_SERVER_CREDENTIAL_TYPES,
+        JMX_CREDENTIAL_TYPES.clone());
+    // Scope the JEP 290 deserialization filter to the credentials object
+    // only, so legitimate JMX RMI traffic (MBean operations, notifications,
+    // etc.) is not affected by the restrictive allowlist.
+    env.put(JMX_REMOTE_RMI_SERVER_CREDENTIALS_FILTER_PATTERN,
+        JMX_CREDENTIAL_SERIAL_FILTER);
+  }
+
   /**
    * Closes this connection handler so that it will no longer accept new
    * client connections. It may or may not disconnect existing client

--
Gitblit v1.10.0