VYPR
Critical severityNVD Advisory· Published Jun 28, 2018· Updated Sep 16, 2024

CVE-2018-8016

CVE-2018-8016

Description

The default configuration in Apache Cassandra 3.8 through 3.11.1 binds an unauthenticated JMX/RMI interface to all network interfaces, which allows remote attackers to execute arbitrary Java code via an RMI request. This issue is a regression of CVE-2015-0225. The regression was introduced in https://issues.apache.org/jira/browse/CASSANDRA-12109. The fix for the regression is implemented in https://issues.apache.org/jira/browse/CASSANDRA-14173. This fix is contained in the 3.11.2 release of Apache Cassandra.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Apache Cassandra 3.8-3.11.1 default configuration exposes unauthenticated JMX/RMI interface, allowing remote code execution via RMI.

Vulnerability

The default configuration in Apache Cassandra versions 3.8 through 3.11.1 binds an unauthenticated JMX/RMI interface to all network interfaces [2]. This is a regression of CVE-2015-0225 introduced by CASSANDRA-12109 [2]. The JMX server uses programmatic configuration that depends on JDK internal classes, making it insecure by default [1][3].

Exploitation

An attacker can send an RMI request to the exposed JMX/RMI interface without authentication. No special network position or user interaction is required; the interface is bound to all network interfaces, making it remotely accessible [2].

Impact

Successful exploitation allows remote attackers to execute arbitrary Java code on the Cassandra node, leading to full compromise of the host [2].

Mitigation

The fix is implemented in CASSANDRA-14173 and is included in Apache Cassandra 3.11.2 [2]. Users should upgrade to 3.11.2 or later. If upgrading is not possible, ensure the JMX/RMI interface is not exposed to untrusted networks [2][3].

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.cassandra:cassandra-allMaven
>= 3.8, < 3.11.23.11.2

Affected products

2

Patches

1
28ee665b3c0c

Remove dependencies on JVM internals for JMX support

https://github.com/beobal/cassandraSam TunnicliffeJan 26, 2018via ghsa
2 files changed · +36 149
  • CHANGES.txt+1 0 modified
    @@ -1,4 +1,5 @@
     3.11.2
    + * Remove dependencies on JVM internal classes from JMXServerUtils (CASSANDRA-14173) 
      * Add DEFAULT, UNSET, MBEAN and MBEANS to `ReservedKeywords` (CASSANDRA-14205)
      * Add Unittest for schema migration fix (CASSANDRA-14140)
      * Print correct snitch info from nodetool describecluster (CASSANDRA-13528)
    
  • src/java/org/apache/cassandra/utils/JMXServerUtils.java+35 149 modified
    @@ -24,16 +24,17 @@
     import java.lang.reflect.Proxy;
     import java.net.Inet6Address;
     import java.net.InetAddress;
    -import java.rmi.*;
    +import java.rmi.registry.LocateRegistry;
    +import java.rmi.registry.Registry;
     import java.rmi.server.RMIClientSocketFactory;
     import java.rmi.server.RMIServerSocketFactory;
    -import java.rmi.server.UnicastRemoteObject;
     import java.util.Arrays;
     import java.util.HashMap;
     import java.util.Map;
     import java.util.stream.Collectors;
     import javax.management.remote.*;
     import javax.management.remote.rmi.RMIConnectorServer;
    +import javax.management.remote.rmi.RMIJRMPServerImpl;
     import javax.rmi.ssl.SslRMIClientSocketFactory;
     import javax.rmi.ssl.SslRMIServerSocketFactory;
     import javax.security.auth.Subject;
    @@ -43,22 +44,18 @@
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
    -import com.sun.jmx.remote.internal.RMIExporter;
     import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
     import org.apache.cassandra.auth.jmx.AuthenticationProxy;
    -import sun.rmi.registry.RegistryImpl;
    -import sun.rmi.server.UnicastServerRef2;
     
     public class JMXServerUtils
     {
         private static final Logger logger = LoggerFactory.getLogger(JMXServerUtils.class);
     
    -    private static java.rmi.registry.Registry registry;
    -
         /**
          * Creates a server programmatically. This allows us to set parameters which normally are
          * inaccessable.
          */
    +    @SuppressWarnings("resource")
         public static JMXConnectorServer createJMXServer(int port, boolean local)
         throws IOException
         {
    @@ -74,6 +71,10 @@ public static JMXConnectorServer createJMXServer(int port, boolean local)
             // Configure the RMI client & server socket factories, including SSL config.
             env.putAll(configureJmxSocketFactories(serverAddress, local));
     
    +        // configure the RMI registry to use the socket factories we just created
    +        Registry registry = LocateRegistry.createRegistry(port,
    +                                                          (RMIClientSocketFactory) env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE),
    +                                                          (RMIServerSocketFactory) env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE));
     
             // Configure authn, using a JMXAuthenticator which either wraps a set log LoginModules configured
             // via a JAAS configuration entry, or one which delegates to the standard file based authenticator.
    @@ -86,48 +87,44 @@ public static JMXConnectorServer createJMXServer(int port, boolean local)
             // If neither method is specified, no access control is applied
             MBeanServerForwarder authzProxy = configureJmxAuthorization(env);
     
    -        // Make sure we use our custom exporter so a full GC doesn't get scheduled every
    -        // sun.rmi.dgc.server.gcInterval millis (default is 3600000ms/1 hour)
    -        env.put(RMIExporter.EXPORTER_ATTRIBUTE, new Exporter());
    -
    -
    +        // Mark the JMX server as a permanently exported object. This allows the JVM to exit with the
    +        // server running and also exempts it from the distributed GC scheduler which otherwise would
    +        // potentially attempt a full GC every `sun.rmi.dgc.server.gcInterval` millis (default is 3600000ms)
    +        // For more background see:
    +        //   - CASSANDRA-2967
    +        //   - https://www.jclarity.com/2015/01/27/rmi-system-gc-unplugged/
    +        //   - https://bugs.openjdk.java.net/browse/JDK-6760712
    +        env.put("jmx.remote.x.daemon", "true");
    +
    +        // Set the port used to create subsequent connections to exported objects over RMI. This simplifies
    +        // configuration in firewalled environments, but it can't be used in conjuction with SSL sockets.
    +        // See: CASSANDRA-7087
             int rmiPort = Integer.getInteger("com.sun.management.jmxremote.rmi.port", 0);
    -        JMXConnectorServer jmxServer =
    -            JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL("rmi", null, rmiPort),
    -                                                            env,
    -                                                            ManagementFactory.getPlatformMBeanServer());
    +
    +        // We create the underlying RMIJRMPServerImpl so that we can manually bind it to the registry,
    +        // rather then specifying a binding address in the JMXServiceURL and letting it be done automatically
    +        // when the server is started. The reason for this is that if the registry is configured with SSL
    +        // sockets, the JMXConnectorServer acts as its client during the binding which means it needs to
    +        // have a truststore configured which contains the registry's certificate. Manually binding removes
    +        // this problem.
    +        // See CASSANDRA-12109.
    +        RMIJRMPServerImpl server = new RMIJRMPServerImpl(rmiPort,
    +                                                         (RMIClientSocketFactory) env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE),
    +                                                         (RMIServerSocketFactory) env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE),
    +                                                         env);
    +        JMXServiceURL serviceURL = new JMXServiceURL("rmi", null, rmiPort);
    +        RMIConnectorServer jmxServer = new RMIConnectorServer(serviceURL, env, server, ManagementFactory.getPlatformMBeanServer());
     
             // If a custom authz proxy was created, attach it to the server now.
             if (authzProxy != null)
                 jmxServer.setMBeanServerForwarder(authzProxy);
    -
             jmxServer.start();
     
    -        // use a custom Registry to avoid having to interact with it internally using the remoting interface
    -        configureRMIRegistry(port, env);
    -
    +        registry.rebind("jmxrmi", server);
             logJmxServiceUrl(serverAddress, port);
             return jmxServer;
         }
     
    -    private static void configureRMIRegistry(int port, Map<String, Object> env) throws RemoteException
    -    {
    -        Exporter exporter = (Exporter)env.get(RMIExporter.EXPORTER_ATTRIBUTE);
    -        // If ssl is enabled, make sure it's also in place for the RMI registry
    -        // by using the SSL socket factories already created and stashed in env
    -        if (Boolean.getBoolean("com.sun.management.jmxremote.ssl"))
    -        {
    -            registry = new Registry(port,
    -                                   (RMIClientSocketFactory)env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE),
    -                                   (RMIServerSocketFactory)env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE),
    -                                   exporter.connectorServer);
    -        }
    -        else
    -        {
    -            registry = new Registry(port, exporter.connectorServer);
    -        }
    -    }
    -
         private static Map<String, Object> configureJmxAuthentication()
         {
             Map<String, Object> env = new HashMap<>();
    @@ -275,115 +272,4 @@ public Subject authenticate(Object credentials)
                 return authenticator.authenticate(credentials);
             }
         }
    -
    -    /**
    -     * In the RMI subsystem, the ObjectTable instance holds references to remote
    -     * objects for distributed garbage collection purposes. When objects are
    -     * added to the ObjectTable (exported), a flag is passed to * indicate the
    -     * "permanence" of that object. Exporting as permanent has two effects; the
    -     * object is not eligible for distributed garbage collection, and its
    -     * existence will not prevent the JVM from exiting after termination of all
    -     * non-daemon threads terminate. Neither of these is bad for our case, as we
    -     * attach the server exactly once (i.e. at startup, not subsequently using
    -     * the Attach API) and don't disconnect it before shutdown. The primary
    -     * benefit we gain is that it doesn't trigger the scheduled full GC that
    -     * is otherwise incurred by programatically configuring the management server.
    -     *
    -     * To that end, we use this private implementation of RMIExporter to register
    -     * our JMXConnectorServer as a permanent object by adding it to the map of
    -     * environment variables under the key RMIExporter.EXPORTER_ATTRIBUTE
    -     * (com.sun.jmx.remote.rmi.exporter) prior to calling server.start()
    -     *
    -     * See also:
    -     *  * CASSANDRA-2967 for background
    -     *  * https://www.jclarity.com/2015/01/27/rmi-system-gc-unplugged/ for more detail
    -     *  * https://bugs.openjdk.java.net/browse/JDK-6760712 for info on setting the exporter
    -     *  * sun.management.remote.ConnectorBootstrap to trace how the inbuilt management agent
    -     *    sets up the JMXConnectorServer
    -     */
    -    private static class Exporter implements RMIExporter
    -    {
    -        // the first object to be exported by this instance is *always* the JMXConnectorServer
    -        // instance created by createJMXServer. Keep a handle to it, as it needs to be supplied
    -        // to our custom Registry too.
    -        private Remote connectorServer;
    -
    -        public Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
    -        throws RemoteException
    -        {
    -            Remote remote = new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true);
    -            // Keep a reference to the first object exported, the JMXConnectorServer
    -            if (connectorServer == null)
    -                connectorServer = remote;
    -
    -            return remote;
    -        }
    -
    -        public boolean unexportObject(Remote obj, boolean force) throws NoSuchObjectException
    -        {
    -            return UnicastRemoteObject.unexportObject(obj, force);
    -        }
    -    }
    -
    -    /**
    -     * Using this class avoids the necessity to interact with the registry via its
    -     * remoting interface. This is necessary because when SSL is enabled for the registry,
    -     * that remote interaction is treated just the same as one from an external client.
    -     * That is problematic when binding the JMXConnectorServer to the Registry as it requires
    -     * the client, which in this case is our own internal code, to connect like any other SSL
    -     * client, meaning we need a truststore containing our own certificate.
    -     * This bypasses the binding API completely, which emulates the behaviour of
    -     * ConnectorBootstrap when the subsystem is initialized by the JVM Agent directly.
    -     *
    -     * See CASSANDRA-12109.
    -     */
    -    private static class Registry extends RegistryImpl
    -    {
    -        private final static String KEY = "jmxrmi";
    -        private final Remote connectorServer;
    -
    -        private Registry(int port, Remote connectorServer) throws RemoteException
    -        {
    -            super(port);
    -            this.connectorServer = connectorServer;
    -        }
    -
    -        private Registry(int port,
    -                         RMIClientSocketFactory csf,
    -                         RMIServerSocketFactory ssf,
    -                         Remote connectorServer) throws RemoteException
    -        {
    -            super(port, csf, ssf);
    -            this.connectorServer = connectorServer;
    -        }
    -
    -        public Remote lookup(String name) throws RemoteException, NotBoundException
    -        {
    -            if (name.equals(KEY))
    -                return connectorServer;
    -
    -            throw new NotBoundException(String.format("Only the JMX Connector Server named %s " +
    -                                                      "is bound in this registry", KEY));
    -        }
    -
    -        public void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException
    -        {
    -            throw new UnsupportedOperationException("Unsupported");
    -        }
    -
    -        public void unbind(String name) throws RemoteException, NotBoundException
    -        {
    -            throw new UnsupportedOperationException("Unsupported");
    -        }
    -
    -        public void rebind(String name, Remote obj) throws RemoteException
    -        {
    -            throw new UnsupportedOperationException("Unsupported");
    -        }
    -
    -        public String[] list() throws RemoteException
    -        {
    -            return new String[] {KEY};
    -        }
    -    }
     }
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.