Moderate severityNVD Advisory· Published May 27, 2023· Updated Jan 13, 2025
Insufficient validation when decoding a Socket.IO packet
CVE-2023-32695
Description
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.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
socket.io-parsernpm | >= 4.0.4, < 4.2.3 | 4.2.3 |
socket.io-parsernpm | >= 3.4.0, < 3.4.3 | 3.4.3 |
socket.io-parsernpm | < 3.3.4 | 3.3.4 |
Affected products
1- Range: >= 4.0.0, < 4.2.3
Patches
4ee006607495efix: check the format of the event name (#125)
3 files changed · +38 −11
index.js+22 −3 modified@@ -268,6 +268,26 @@ Decoder.prototype.add = function(obj) { } }; +function isPayloadValid(type, payload) { + switch (type) { + case 0: // CONNECT + return typeof payload === "object"; + case 1: // DISCONNECT + return payload === undefined; + case 4: // ERROR + return typeof payload === "string" || typeof payload === "object"; + case 2: // EVENT + case 5: // BINARY_EVENT + return ( + isArray(payload) && + (typeof payload[0] === "string" || typeof payload[0] === "number") + ); + case 3: // ACK + case 6: // BINARY_ACK + return isArray(payload); + } +} + /** * Decode a packet String (JSON data) * @@ -329,11 +349,10 @@ function decodeString(str) { // look up json data if (str.charAt(++i)) { var payload = tryParse(str.substr(i)); - var isPayloadValid = payload !== false && (p.type === exports.ERROR || isArray(payload)); - if (isPayloadValid) { + if (isPayloadValid(p.type, payload)) { p.data = payload; } else { - return error('invalid payload'); + throw new Error("invalid payload"); } }
test/arraybuffer.js+1 −1 modified@@ -50,7 +50,7 @@ describe('parser', function() { it('cleans itself up on close', function() { var packet = { type: parser.BINARY_EVENT, - data: [new ArrayBuffer(2), new ArrayBuffer(3)], + data: ["foo", new ArrayBuffer(2), new ArrayBuffer(3)], id: 0, nsp: '/' };
test/parser.js+15 −7 modified@@ -86,12 +86,20 @@ describe('parser', function(){ } }); - it('returns an error packet on parsing error', function(done){ - var decoder = new parser.Decoder(); - decoder.on('decoded', function(packet) { - expect(packet).to.eql({ type: 4, data: 'parser error: invalid payload' }); - done(); - }); - decoder.add('442["some","data"'); + it('returns an error packet on parsing error', function(){ + function isInvalidPayload (str) { + expect(function () { + new parser.Decoder().add(str) + }).to.throwException(/^invalid payload$/); + } + + 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"]'); }); });
2dc3c92622dafix: check the format of the event name
3 files changed · +38 −11
index.js+22 −3 modified@@ -329,11 +329,10 @@ function decodeString(str) { // look up json data if (str.charAt(++i)) { var payload = tryParse(str.substr(i)); - var isPayloadValid = payload !== false && (p.type === exports.ERROR || isArray(payload)); - if (isPayloadValid) { + if (isPayloadValid(p.type, payload)) { p.data = payload; } else { - return error('invalid payload'); + throw new Error("invalid payload"); } } @@ -349,6 +348,26 @@ function tryParse(str) { } } +function isPayloadValid(type, payload) { + switch (type) { + case 0: // CONNECT + return typeof payload === "object"; + case 1: // DISCONNECT + return payload === undefined; + case 4: // ERROR + return typeof payload === "string" || typeof payload === "object"; + case 2: // EVENT + case 5: // BINARY_EVENT + return ( + isArray(payload) && + (typeof payload[0] === "string" || typeof payload[0] === "number") + ); + case 3: // ACK + case 6: // BINARY_ACK + return isArray(payload); + } +} + /** * Deallocates a parser's resources *
test/arraybuffer.js+1 −1 modified@@ -50,7 +50,7 @@ describe('parser', function() { it('cleans itself up on close', function() { var packet = { type: parser.BINARY_EVENT, - data: [new ArrayBuffer(2), new ArrayBuffer(3)], + data: ["foo", new ArrayBuffer(2), new ArrayBuffer(3)], id: 0, nsp: '/' };
test/parser.js+15 −7 modified@@ -86,12 +86,20 @@ describe('parser', function(){ } }); - it('returns an error packet on parsing error', function(done){ - var decoder = new parser.Decoder(); - decoder.on('decoded', function(packet) { - expect(packet).to.eql({ type: 4, data: 'parser error: invalid payload' }); - done(); - }); - decoder.add('442["some","data"'); + it('returns an error packet on parsing error', function(){ + function isInvalidPayload (str) { + expect(function () { + new parser.Decoder().add(str) + }).to.throwException(/^invalid payload$/); + } + + 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"]'); }); });
3b78117bf6bafix: check the format of the event name
2 files changed · +7 −1
lib/index.ts+4 −1 modified@@ -275,7 +275,10 @@ export class Decoder extends Emitter<{}, {}, DecoderReservedEvents> { 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);
test/parser.js+3 −0 modified@@ -118,6 +118,9 @@ describe("socket.io-parser", () => { 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$/
1c220ddbf45efix: allow integers as event names
2 files changed · +12 −1
lib/index.ts+1 −1 modified@@ -245,7 +245,7 @@ export class Decoder extends Emitter { return typeof payload === "string" || typeof payload === "object"; case PacketType.EVENT: case PacketType.BINARY_EVENT: - return Array.isArray(payload) && typeof payload[0] === "string"; + return Array.isArray(payload) && payload.length > 0; case PacketType.ACK: case PacketType.BINARY_ACK: return Array.isArray(payload);
test/parser.js+11 −0 modified@@ -47,6 +47,17 @@ describe("parser", () => { ); }); + it("encodes an event (with an integer as event name)", (done) => { + helpers.test( + { + type: PacketType.EVENT, + data: [1, "a", {}], + nsp: "/", + }, + done + ); + }); + it("encodes an event (with ack)", (done) => { helpers.test( {
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
8- github.com/advisories/GHSA-cqmj-92xf-r6r9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-32695ghsaADVISORY
- github.com/socketio/socket.io-parser/commit/1c220ddbf45ea4b44bc8dbf6f9ae245f672ba1b9ghsaWEB
- github.com/socketio/socket.io-parser/commit/2dc3c92622dad113b8676be06f23b1ed46b02cedghsax_refsource_MISCWEB
- github.com/socketio/socket.io-parser/commit/3b78117bf6ba7e99d7a5cfc1ba54d0477554a7f3ghsax_refsource_MISCWEB
- github.com/socketio/socket.io-parser/commit/ee006607495eca4ec7262ad080dd3a91439a5ba4ghsaWEB
- github.com/socketio/socket.io-parser/releases/tag/4.2.3ghsax_refsource_MISCWEB
- github.com/socketio/socket.io-parser/security/advisories/GHSA-cqmj-92xf-r6r9ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.