CVE-2016-10544: Improper Input Validation (CWE-20)
value: uws is a WebSocket server library. By sending a 256mb websocket message to a uws server instance with permessage-deflate enabled, there is a possibility used compression will shrink said 256mb down to less than 16mb of websocket payload which passes the length check of 16mb payload. This data will then inflate up to 256mb and crash the node process by exceeding V8's maximum string size. This affects uws >=0.10.0 <=0.10.8.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 5.9
Published: 2018-05-31T20:29Z
Repository: https://github.com/uWebSockets/uWebSockets
Language: C++
Files changed: src/Hub.cpp, src/WebSocketImpl.cpp
Commit date: 2016-10-13 23:19:43 +0200
Commit message: Don't inflate more than ~16mb, drop connection on inflate error

Diff: diff --git a/src/Hub.cpp b/src/Hub.cpp
index 3502008..6ff96a4 100644
--- a/src/Hub.cpp
+++ b/src/Hub.cpp
@@ -1,9 +1,11 @@
 #include "Hub.h"
 #include "HTTPSocket.h"
 #include <openssl/sha.h>
 
+static const int INFLATE_LESS_THAN_ROUGHLY = 16777216;
+
 namespace uWS {
 
 char *Hub::inflate(char *data, size_t &length) {
     dynamicInflationBuffer.clear();
 
@@ -16,16 +18,17 @@ char *Hub::inflate(char *data, size_t &length) {
         inflationStream.avail_out = LARGE_BUFFER_SIZE;
         err = ::inflate(&inflationStream, Z_FINISH);
         if (!inflationStream.avail_in) {
             break;
         }
+
         dynamicInflationBuffer.append(inflationBuffer, LARGE_BUFFER_SIZE - inflationStream.avail_out);
-    } while (err == Z_BUF_ERROR);
+    } while (err == Z_BUF_ERROR && dynamicInflationBuffer.length() <= INFLATE_LESS_THAN_ROUGHLY);
 
     inflateReset(&inflationStream);
 
-    if (err != Z_BUF_ERROR && err != Z_OK) {
+    if ((err != Z_BUF_ERROR && err != Z_OK) || dynamicInflationBuffer.length() > INFLATE_LESS_THAN_ROUGHLY) {
         length = 0;
         return nullptr;
     }
 
     if (dynamicInflationBuffer.length()) {
diff --git a/src/WebSocketImpl.cpp b/src/WebSocketImpl.cpp
index 976ba7c..e9d91ca 100644
--- a/src/WebSocketImpl.cpp
+++ b/src/WebSocketImpl.cpp
@@ -34,10 +34,14 @@ bool WebSocketProtocol<isServer>::handleFragment(char *data, size_t length, unsi
         if (!remainingBytes && fin && !webSocketData->fragmentBuffer.length()) {
             if (webSocketData->compressionStatus == WebSocket<isServer>::Data::CompressionStatus::COMPRESSED_FRAME) {
                 webSocketData->compressionStatus = WebSocket<isServer>::Data::CompressionStatus::ENABLED;
                 Hub *hub = ((Group<isServer> *) s.getSocketData()->nodeData)->hub;
                 data = hub->inflate(data, length);
+                if (!data) {
+                    forceClose(user);
+                    return true;
+                }
             }
 
             if (opCode == 1 && !isValidUtf8((unsigned char *) data, length)) {
                 forceClose(user);
                 return true;
@@ -54,10 +58,14 @@ bool WebSocketProtocol<isServer>::handleFragment(char *data, size_t length, unsi
                 if (webSocketData->compressionStatus == WebSocket<isServer>::Data::CompressionStatus::COMPRESSED_FRAME) {
                     webSocketData->compressionStatus = WebSocket<isServer>::Data::CompressionStatus::ENABLED;
                     Hub *hub = ((Group<isServer> *) s.getSocketData()->nodeData)->hub;
                     webSocketData->fragmentBuffer.append("....");
                     data = hub->inflate((char *) webSocketData->fragmentBuffer.data(), length);
+                    if (!data) {
+                        forceClose(user);
+                        return true;
+                    }
                 } else {
                     data = (char *) webSocketData->fragmentBuffer.data();
                 }
 
                 if (opCode == 1 && !isValidUtf8((unsigned char *) data, length)) {

Vulnerable code:     } while (err == Z_BUF_ERROR);
    if (err != Z_BUF_ERROR && err != Z_OK) {
Fixed code: static const int INFLATE_LESS_THAN_ROUGHLY = 16777216;


    } while (err == Z_BUF_ERROR && dynamicInflationBuffer.length() <= INFLATE_LESS_THAN_ROUGHLY);
    if ((err != Z_BUF_ERROR && err != Z_OK) || dynamicInflationBuffer.length() > INFLATE_LESS_THAN_ROUGHLY) {
                if (!data) {
                    forceClose(user);
                    return true;
                }
                    if (!data) {
                        forceClose(user);
                        return true;
                    }