VYPR
High severityNVD Advisory· Published Feb 10, 2025· Updated Apr 16, 2025

SslHandler doesn't correctly validate packets which can lead to native crash when using native SSLEngine

CVE-2025-24970

Description

Netty, an asynchronous, event-driven network application framework, has a vulnerability starting in version 4.1.91.Final and prior to version 4.1.118.Final. When a special crafted packet is received via SslHandler it doesn't correctly handle validation of such a packet in all cases which can lead to a native crash. Version 4.1.118.Final contains a patch. As workaround its possible to either disable the usage of the native SSLEngine or change the code manually.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
io.netty:netty-handlerMaven
>= 4.1.91.Final, < 4.1.118.Final4.1.118.Final

Affected products

1
  • Range: >= 4.1.91.Final, <= 4.1.117.Final

Patches

1
87f40725155b

Merge commit from fork

https://github.com/netty/nettyNorman MaurerFeb 10, 2025via ghsa
2 files changed · +19 6
  • handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java+2 0 modified
    @@ -1202,6 +1202,8 @@ public final SSLEngineResult unwrap(
                         throw new NotSslRecordException("not an SSL/TLS record");
                     }
     
    +                assert packetLength >= 0;
    +
                     final int packetLengthDataOnly = packetLength - SSL_RECORD_HEADER_LENGTH;
                     if (packetLengthDataOnly > capacity) {
                         // Not enough space in the destination buffer so signal the caller that the buffer needs to be
    
  • handler/src/main/java/io/netty/handler/ssl/SslUtils.java+17 6 modified
    @@ -314,8 +314,12 @@ static SSLHandshakeException toSSLHandshakeException(Throwable e) {
          *                      the given {@link ByteBuf} is not encrypted at all.
          */
         static int getEncryptedPacketLength(ByteBuf buffer, int offset, boolean probeSSLv2) {
    +        assert offset >= buffer.readerIndex();
    +        int remaining = buffer.writerIndex() - offset;
    +        if (remaining < SSL_RECORD_HEADER_LENGTH) {
    +            return NOT_ENOUGH_DATA;
    +        }
             int packetLength = 0;
    -
             // SSLv3 or TLS - Check ContentType
             boolean tls;
             switch (buffer.getUnsignedByte(offset)) {
    @@ -346,7 +350,7 @@ static int getEncryptedPacketLength(ByteBuf buffer, int offset, boolean probeSSL
                         tls = false;
                     }
                 } else if (version == DTLS_1_0 || version == DTLS_1_2 || version == DTLS_1_3) {
    -                if (buffer.readableBytes() < offset + DTLS_RECORD_HEADER_LENGTH) {
    +                if (remaining < DTLS_RECORD_HEADER_LENGTH) {
                         return NOT_ENOUGH_DATA;
                     }
                     // length is the last 2 bytes in the 13 byte header.
    @@ -367,7 +371,8 @@ static int getEncryptedPacketLength(ByteBuf buffer, int offset, boolean probeSSL
                     packetLength = headerLength == 2 ?
                             (shortBE(buffer, offset) & 0x7FFF) + 2 : (shortBE(buffer, offset) & 0x3FFF) + 3;
                     if (packetLength <= headerLength) {
    -                    return NOT_ENOUGH_DATA;
    +                    // If there's no data then consider this package as not encrypted.
    +                    return NOT_ENCRYPTED;
                     }
                 } else {
                     return NOT_ENCRYPTED;
    @@ -420,24 +425,29 @@ static int getEncryptedPacketLength(ByteBuffer[] buffers, int offset) {
             }
     
             // We need to copy 5 bytes into a temporary buffer so we can parse out the packet length easily.
    -        ByteBuffer tmp = ByteBuffer.allocate(5);
    +        ByteBuffer tmp = ByteBuffer.allocate(SSL_RECORD_HEADER_LENGTH);
     
             do {
                 buffer = buffers[offset++].duplicate();
                 if (buffer.remaining() > tmp.remaining()) {
                     buffer.limit(buffer.position() + tmp.remaining());
                 }
                 tmp.put(buffer);
    -        } while (tmp.hasRemaining());
    +        } while (tmp.hasRemaining() && offset < buffers.length);
     
             // Done, flip the buffer so we can read from it.
             tmp.flip();
             return getEncryptedPacketLength(tmp);
         }
     
         private static int getEncryptedPacketLength(ByteBuffer buffer) {
    +        int remaining = buffer.remaining();
    +        if (remaining < SSL_RECORD_HEADER_LENGTH) {
    +            return NOT_ENOUGH_DATA;
    +        }
             int packetLength = 0;
             int pos = buffer.position();
    +
             // SSLv3 or TLS - Check ContentType
             boolean tls;
             switch (unsignedByte(buffer.get(pos))) {
    @@ -478,7 +488,8 @@ private static int getEncryptedPacketLength(ByteBuffer buffer) {
                     packetLength = headerLength == 2 ?
                             (shortBE(buffer, pos) & 0x7FFF) + 2 : (shortBE(buffer, pos) & 0x3FFF) + 3;
                     if (packetLength <= headerLength) {
    -                    return NOT_ENOUGH_DATA;
    +                    // If there's no data then consider this package as not encrypted.
    +                    return NOT_ENCRYPTED;
                     }
                 } else {
                     return NOT_ENCRYPTED;
    

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

7

News mentions

0

No linked articles in our index yet.