VYPR
Medium severity5.4NVD Advisory· Published Apr 2, 2024· Updated Apr 15, 2026

CVE-2024-1300

CVE-2024-1300

Description

A vulnerability in the Eclipse Vert.x toolkit causes a memory leak in TCP servers configured with TLS and SNI support. When processing an unknown SNI server name assigned the default certificate instead of a mapped certificate, the SSL context is erroneously cached in the server name map, leading to memory exhaustion. This flaw allows attackers to send TLS client hello messages with fake server names, triggering a JVM out-of-memory error.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
io.vertx:vertx-coreMaven
>= 4.3.4, < 4.4.84.4.8
io.vertx:vertx-coreMaven
>= 4.5.0, < 4.5.34.5.3

Patches

2
7ad34ea9d78f

The SslChannelProvider class maintains a map of server name to Netty SslContext that is filled when a client provides a server name. When a server name does not resolve to a KeyManagerFactory or TrustManagerFactory, the default factories are used and the entry is stored in the map. Instead no specific factory is resolved the default Netty SslContext is used, since this can lead to a a memory leak when a client specifies spurious SNI server names. This affects only a TCP server when SNI is set in the HttpServerOptions.

https://github.com/eclipse-vertx/vert.xJulien VietFeb 5, 2024via ghsa
5 files changed · +39 40
  • src/main/java/io/vertx/core/net/impl/SslChannelProvider.java+13 8 modified
    @@ -65,6 +65,10 @@ public SslChannelProvider(SslContextProvider sslContextProvider,
         this.sslContextProvider = sslContextProvider;
       }
     
    +  public int sniEntrySize() {
    +    return sslContextMaps[0].size() + sslContextMaps[1].size();
    +  }
    +
       public SslContextProvider sslContextProvider() {
         return sslContextProvider;
       }
    @@ -83,17 +87,18 @@ public SslContext sslClientContext(String serverName, boolean useAlpn, boolean t
     
       public SslContext sslContext(String serverName, boolean useAlpn, boolean server, boolean trustAll) throws Exception {
         int idx = idx(useAlpn);
    -    if (serverName == null) {
    -      if (sslContexts[idx] == null) {
    -        SslContext context = sslContextProvider.createContext(server, null, null, null, useAlpn, trustAll);
    -        sslContexts[idx] = context;
    -      }
    -      return sslContexts[idx];
    -    } else {
    +    if (serverName != null) {
           KeyManagerFactory kmf = sslContextProvider.resolveKeyManagerFactory(serverName);
           TrustManager[] trustManagers = trustAll ? null : sslContextProvider.resolveTrustManagers(serverName);
    -      return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll));
    +      if (kmf != null || trustManagers != null || !server) {
    +        return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll));
    +      }
    +    }
    +    if (sslContexts[idx] == null) {
    +      SslContext context = sslContextProvider.createContext(server, null, null, serverName, useAlpn, trustAll);
    +      sslContexts[idx] = context;
         }
    +    return sslContexts[idx];
       }
     
       public SslContext sslServerContext(boolean useAlpn) {
    
  • src/main/java/io/vertx/core/net/impl/SslContextProvider.java+7 25 modified
    @@ -154,13 +154,6 @@ protected void initEngine(SSLEngine engine) {
         }
       }
     
    -  public KeyManagerFactory loadKeyManagerFactory(String serverName) throws Exception {
    -    if (keyManagerFactoryMapper != null) {
    -      return keyManagerFactoryMapper.apply(serverName);
    -    }
    -    return null;
    -  }
    -
       public TrustManager[] defaultTrustManagers() {
         return trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null;
       }
    @@ -174,8 +167,7 @@ public KeyManagerFactory defaultKeyManagerFactory() {
       }
     
       /**
    -   * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, the default
    -   * factory is returned.
    +   * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, {@code null} is returned.
        * <br/>
        * This can block and should be executed on the appropriate thread.
        *
    @@ -184,23 +176,14 @@ public KeyManagerFactory defaultKeyManagerFactory() {
        * @throws Exception anything that would prevent loading the factory
        */
       public KeyManagerFactory resolveKeyManagerFactory(String serverName) throws Exception {
    -    KeyManagerFactory kmf = loadKeyManagerFactory(serverName);
    -    if (kmf == null) {
    -      kmf = keyManagerFactory;
    -    }
    -    return kmf;
    -  }
    -
    -  public TrustManager[] loadTrustManagers(String serverName) throws Exception {
    -    if (trustManagerMapper != null) {
    -      return trustManagerMapper.apply(serverName);
    +    if (keyManagerFactoryMapper != null) {
    +      return keyManagerFactoryMapper.apply(serverName);
         }
         return null;
       }
     
       /**
    -   * Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, the default
    -   * managers are returned.
    +   * Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, {@code null} is returned.
        * <br/>
        * This can block and should be executed on the appropriate thread.
        *
    @@ -209,11 +192,10 @@ public TrustManager[] loadTrustManagers(String serverName) throws Exception {
        * @throws Exception anything that would prevent loading the managers
        */
       public TrustManager[] resolveTrustManagers(String serverName) throws Exception {
    -    TrustManager[] trustManagers = loadTrustManagers(serverName);
    -    if (trustManagers == null && trustManagerFactory != null) {
    -      trustManagers = trustManagerFactory.getTrustManagers();
    +    if (trustManagerMapper != null) {
    +      return trustManagerMapper.apply(serverName);
         }
    -    return trustManagers;
    +    return null;
       }
     
       private VertxTrustManagerFactory buildVertxTrustManagerFactory(TrustManager[] mgrs) {
    
  • src/main/java/io/vertx/core/net/impl/SSLHelper.java+8 0 modified
    @@ -126,6 +126,14 @@ public SSLHelper(TCPSSLOptions options, List<String> applicationProtocols) {
         this.applicationProtocols = applicationProtocols;
       }
     
    +  public synchronized int sniEntrySize() {
    +    CachedProvider res = cachedProvider.result();
    +    if (res != null) {
    +      return res.sslChannelProvider.sniEntrySize();
    +    }
    +    return 0;
    +  }
    +
       private static class CachedProvider {
         final SSLOptions options;
         final long id;
    
  • src/main/java/io/vertx/core/net/impl/TCPServerBase.java+4 0 modified
    @@ -125,6 +125,10 @@ private GlobalTrafficShapingHandler createTrafficShapingHandler(EventLoopGroup e
         return trafficShapingHandler;
       }
     
    +  public int sniEntrySize() {
    +    return sslHelper.sniEntrySize();
    +  }
    +
       public Future<Boolean> updateSSLOptions(SSLOptions options, boolean force) {
         TCPServerBase server = actualServer;
         if (server != null && server != this) {
    
  • src/test/java/io/vertx/core/net/NetTest.java+7 7 modified
    @@ -58,10 +58,7 @@
     import io.vertx.core.impl.logging.LoggerFactory;
     import io.vertx.core.json.JsonArray;
     import io.vertx.core.json.JsonObject;
    -import io.vertx.core.net.impl.HAProxyMessageCompletionHandler;
    -import io.vertx.core.net.impl.NetServerImpl;
    -import io.vertx.core.net.impl.NetSocketInternal;
    -import io.vertx.core.net.impl.VertxHandler;
    +import io.vertx.core.net.impl.*;
     import io.vertx.core.spi.tls.SslContextFactory;
     import io.vertx.core.streams.ReadStream;
     import io.vertx.test.core.CheckingSender;
    @@ -1538,14 +1535,17 @@ public void testClientSniMultipleServerName() throws Exception {
           receivedServerNames.add(so.indicatedServerName());
         });
         startServer();
    -    List<String> serverNames = Arrays.asList("host1", "host2.com");
    +    List<String> serverNames = Arrays.asList("host1", "host2.com", "fake");
    +    List<String> cns = new ArrayList<>();
         client = vertx.createNetClient(new NetClientOptions().setSsl(true).setTrustAll(true));
         for (String serverName : serverNames) {
           NetSocket so = client.connect(testAddress, serverName).toCompletionStage().toCompletableFuture().get();
           String host = cnOf(so.peerCertificates().get(0));
    -      assertEquals(serverName, host);
    +      cns.add(host);
         }
    -    assertWaitUntil(() -> receivedServerNames.size() == 2);
    +    assertEquals(Arrays.asList("host1", "host2.com", "localhost"), cns);
    +    assertEquals(2, ((TCPServerBase)server).sniEntrySize());
    +    assertWaitUntil(() -> receivedServerNames.size() == 3);
         assertEquals(receivedServerNames, serverNames);
       }
     
    
3d9235cadf44

The SslChannelProvider class maintains a map of server name to Netty SslContext that is filled when a client provides a server name. When a server name does not resolve to a KeyManagerFactory or TrustManagerFactory, the default factories are used and the entry is stored in the map. Instead no specific factory is resolved the default Netty SslContext is used, since this can lead to a a memory leak when a client specifies spurious SNI server names. This affects only a TCP server when SNI is set in the HttpServerOptions.

https://github.com/eclipse-vertx/vert.xJulien VietFeb 5, 2024via ghsa
5 files changed · +39 40
  • src/main/java/io/vertx/core/net/impl/SslChannelProvider.java+13 8 modified
    @@ -65,6 +65,10 @@ public SslChannelProvider(SslContextProvider sslContextProvider,
         this.sslContextProvider = sslContextProvider;
       }
     
    +  public int sniEntrySize() {
    +    return sslContextMaps[0].size() + sslContextMaps[1].size();
    +  }
    +
       public SslContextProvider sslContextProvider() {
         return sslContextProvider;
       }
    @@ -83,17 +87,18 @@ public SslContext sslClientContext(String serverName, boolean useAlpn, boolean t
     
       public SslContext sslContext(String serverName, boolean useAlpn, boolean server, boolean trustAll) throws Exception {
         int idx = idx(useAlpn);
    -    if (serverName == null) {
    -      if (sslContexts[idx] == null) {
    -        SslContext context = sslContextProvider.createContext(server, null, null, null, useAlpn, trustAll);
    -        sslContexts[idx] = context;
    -      }
    -      return sslContexts[idx];
    -    } else {
    +    if (serverName != null) {
           KeyManagerFactory kmf = sslContextProvider.resolveKeyManagerFactory(serverName);
           TrustManager[] trustManagers = trustAll ? null : sslContextProvider.resolveTrustManagers(serverName);
    -      return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll));
    +      if (kmf != null || trustManagers != null || !server) {
    +        return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll));
    +      }
    +    }
    +    if (sslContexts[idx] == null) {
    +      SslContext context = sslContextProvider.createContext(server, null, null, serverName, useAlpn, trustAll);
    +      sslContexts[idx] = context;
         }
    +    return sslContexts[idx];
       }
     
       public SslContext sslServerContext(boolean useAlpn) {
    
  • src/main/java/io/vertx/core/net/impl/SslContextProvider.java+7 25 modified
    @@ -154,13 +154,6 @@ protected void initEngine(SSLEngine engine) {
         }
       }
     
    -  public KeyManagerFactory loadKeyManagerFactory(String serverName) throws Exception {
    -    if (keyManagerFactoryMapper != null) {
    -      return keyManagerFactoryMapper.apply(serverName);
    -    }
    -    return null;
    -  }
    -
       public TrustManager[] defaultTrustManagers() {
         return trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null;
       }
    @@ -174,8 +167,7 @@ public KeyManagerFactory defaultKeyManagerFactory() {
       }
     
       /**
    -   * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, the default
    -   * factory is returned.
    +   * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, {@code null} is returned.
        * <br/>
        * This can block and should be executed on the appropriate thread.
        *
    @@ -184,23 +176,14 @@ public KeyManagerFactory defaultKeyManagerFactory() {
        * @throws Exception anything that would prevent loading the factory
        */
       public KeyManagerFactory resolveKeyManagerFactory(String serverName) throws Exception {
    -    KeyManagerFactory kmf = loadKeyManagerFactory(serverName);
    -    if (kmf == null) {
    -      kmf = keyManagerFactory;
    -    }
    -    return kmf;
    -  }
    -
    -  public TrustManager[] loadTrustManagers(String serverName) throws Exception {
    -    if (trustManagerMapper != null) {
    -      return trustManagerMapper.apply(serverName);
    +    if (keyManagerFactoryMapper != null) {
    +      return keyManagerFactoryMapper.apply(serverName);
         }
         return null;
       }
     
       /**
    -   * Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, the default
    -   * managers are returned.
    +   * Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, {@code null} is returned.
        * <br/>
        * This can block and should be executed on the appropriate thread.
        *
    @@ -209,11 +192,10 @@ public TrustManager[] loadTrustManagers(String serverName) throws Exception {
        * @throws Exception anything that would prevent loading the managers
        */
       public TrustManager[] resolveTrustManagers(String serverName) throws Exception {
    -    TrustManager[] trustManagers = loadTrustManagers(serverName);
    -    if (trustManagers == null && trustManagerFactory != null) {
    -      trustManagers = trustManagerFactory.getTrustManagers();
    +    if (trustManagerMapper != null) {
    +      return trustManagerMapper.apply(serverName);
         }
    -    return trustManagers;
    +    return null;
       }
     
       private VertxTrustManagerFactory buildVertxTrustManagerFactory(TrustManager[] mgrs) {
    
  • src/main/java/io/vertx/core/net/impl/SSLHelper.java+8 0 modified
    @@ -124,6 +124,14 @@ public SSLHelper(TCPSSLOptions options, List<String> applicationProtocols) {
         this.applicationProtocols = applicationProtocols;
       }
     
    +  public synchronized int sniEntrySize() {
    +    CachedProvider res = cachedProvider.result();
    +    if (res != null) {
    +      return res.sslChannelProvider.sniEntrySize();
    +    }
    +    return 0;
    +  }
    +
       private static class CachedProvider {
         final SSLOptions options;
         final SslChannelProvider sslChannelProvider;
    
  • src/main/java/io/vertx/core/net/impl/TCPServerBase.java+4 0 modified
    @@ -127,6 +127,10 @@ private GlobalTrafficShapingHandler createTrafficShapingHandler(EventLoopGroup e
         return trafficShapingHandler;
       }
     
    +  public int sniEntrySize() {
    +    return sslHelper.sniEntrySize();
    +  }
    +
       public Future<Void> updateSSLOptions(SSLOptions options) {
         TCPServerBase server = actualServer;
         if (server != null && server != this) {
    
  • src/test/java/io/vertx/core/net/NetTest.java+7 7 modified
    @@ -58,10 +58,7 @@
     import io.vertx.core.impl.logging.LoggerFactory;
     import io.vertx.core.json.JsonArray;
     import io.vertx.core.json.JsonObject;
    -import io.vertx.core.net.impl.HAProxyMessageCompletionHandler;
    -import io.vertx.core.net.impl.NetServerImpl;
    -import io.vertx.core.net.impl.NetSocketInternal;
    -import io.vertx.core.net.impl.VertxHandler;
    +import io.vertx.core.net.impl.*;
     import io.vertx.core.spi.tls.SslContextFactory;
     import io.vertx.core.streams.ReadStream;
     import io.vertx.test.core.CheckingSender;
    @@ -1536,14 +1533,17 @@ public void testClientSniMultipleServerName() throws Exception {
           receivedServerNames.add(so.indicatedServerName());
         });
         startServer();
    -    List<String> serverNames = Arrays.asList("host1", "host2.com");
    +    List<String> serverNames = Arrays.asList("host1", "host2.com", "fake");
    +    List<String> cns = new ArrayList<>();
         client = vertx.createNetClient(new NetClientOptions().setSsl(true).setTrustAll(true));
         for (String serverName : serverNames) {
           NetSocket so = client.connect(testAddress, serverName).toCompletionStage().toCompletableFuture().get();
           String host = cnOf(so.peerCertificates().get(0));
    -      assertEquals(serverName, host);
    +      cns.add(host);
         }
    -    assertWaitUntil(() -> receivedServerNames.size() == 2);
    +    assertEquals(Arrays.asList("host1", "host2.com", "localhost"), cns);
    +    assertEquals(2, ((TCPServerBase)server).sniEntrySize());
    +    assertWaitUntil(() -> receivedServerNames.size() == 3);
         assertEquals(receivedServerNames, serverNames);
       }
     
    

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

18

News mentions

0

No linked articles in our index yet.