CVE-2023-32695: Improper Check for Unusual or Exceptional Conditions (CWE-754)
value: socket.io parser is a socket.io encoder and decoder written in JavaScript complying with version 5 of socket.io-protocol. A specially crafted Socket.IO packet can trigger an uncaught exception on the Socket.IO server, thus killing the Node.js process. A patch has been released in version 4.2.3.


CWE description: The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product.
CVSS v3 base score: 7.5
Published: 2023-05-27T16:15Z
Repository: https://github.com/socketio/socket.io-parser
Language: JavaScript
Files changed: lib/index.ts, test/parser.js
Commit date: 2023-05-22 08:25:33 +0200
Commit message: fix: check the format of the event name

A packet like '2[{"toString":"foo"}]' was decoded as:

{
  type: EVENT,
  data: [ { "toString": "foo" } ]
}

Which would then throw an error when passed to the EventEmitter class:

> TypeError: Cannot convert object to primitive value
>    at Socket.emit (node:events:507:25)
>    at .../node_modules/socket.io/lib/socket.js:531:14

History of the isPayloadValid() method:

- added in [78f9fc2](https://github.com/socketio/socket.io-parser/commit/78f9fc2999b15804b02f2c22a2b4007734a26af9) (v4.0.1, socket.io@3.0.0)
- updated in [1c220dd](https://github.com/socketio/socket.io-parser/commit/1c220ddbf45ea4b44bc8dbf6f9ae245f672ba1b9) (v4.0.4, socket.io@3.1.0)

Diff: diff --git a/lib/index.ts b/lib/index.ts
index 6b77094..4319d2c 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -273,11 +273,14 @@ export class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
         return payload === undefined;
       case PacketType.CONNECT_ERROR:
         return typeof payload === "string" || typeof payload === "object";
       case PacketType.EVENT:
       case PacketType.BINARY_EVENT:
-        return Array.isArray(payload) && payload.length > 0;
+        return (
+          Array.isArray(payload) &&
+          (typeof payload[0] === "string" || typeof payload[0] === "number")
+        );
       case PacketType.ACK:
       case PacketType.BINARY_ACK:
         return Array.isArray(payload);
     }
   }
diff --git a/test/parser.js b/test/parser.js
index 1b99166..c78e675 100644
--- a/test/parser.js
+++ b/test/parser.js
@@ -116,10 +116,13 @@ describe("socket.io-parser", () => {
     isInvalidPayload('442["some","data"');
     isInvalidPayload('0/admin,"invalid"');
     isInvalidPayload("1/admin,{}");
     isInvalidPayload('2/admin,"invalid');
     isInvalidPayload("2/admin,{}");
+    isInvalidPayload('2[{"toString":"foo"}]');
+    isInvalidPayload('2[true,"foo"]');
+    isInvalidPayload('2[null,"bar"]');
 
     expect(() => new Decoder().add("999")).to.throwException(
       /^unknown packet type 9$/
     );
 

Vulnerable code:         return Array.isArray(payload) && payload.length > 0;
Fixed code:         return (
          Array.isArray(payload) &&
          (typeof payload[0] === "string" || typeof payload[0] === "number")
        );
    isInvalidPayload('2[{"toString":"foo"}]');
    isInvalidPayload('2[true,"foo"]');
    isInvalidPayload('2[null,"bar"]');