VYPR
Critical severityNVD Advisory· Published Oct 25, 2022· Updated Mar 11, 2025

Socket.io - Improper type validation in attachment parsing

CVE-2022-2421

Description

Due to improper type validation in attachment parsing the Socket.io js library, it is possible to overwrite the _placeholder object which allows an attacker to place references to functions at arbitrary places in the resulting query object.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
socket.io-parsernpm
>= 4.0.0, < 4.0.54.0.5
socket.io-parsernpm
>= 4.1.0, < 4.2.14.2.1
socket.io-parsernpm
< 3.3.33.3.3
socket.io-parsernpm
>= 3.4.0, < 3.4.23.4.2

Affected products

1

Patches

4
fb21e422fc19

fix: check the format of the index of each attachment

https://github.com/socketio/socket.io-parserDamien ArrachequesneNov 9, 2022via ghsa
3 files changed · +58 4
  • binary.js+10 2 modified
    @@ -70,8 +70,16 @@ exports.reconstructPacket = function(packet, buffers) {
     function _reconstructPacket(data, buffers) {
       if (!data) return data;
     
    -  if (data && data._placeholder) {
    -    return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +  if (data && data._placeholder === true) {
    +    var isIndexValid =
    +      typeof data.num === "number" &&
    +      data.num >= 0 &&
    +      data.num < buffers.length;
    +    if (isIndexValid) {
    +      return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +    } else {
    +      throw new Error("illegal attachments");
    +    }
       } else if (isArray(data)) {
         for (var i = 0; i < data.length; i++) {
           data[i] = _reconstructPacket(data[i], buffers);
    
  • index.js+3 0 modified
    @@ -239,6 +239,9 @@ Emitter(Decoder.prototype);
     Decoder.prototype.add = function(obj) {
       var packet;
       if (typeof obj === 'string') {
    +    if (this.reconstructor) {
    +      throw new Error("got plaintext data when reconstructing a packet");
    +    }
         packet = decodeString(obj);
         if (exports.BINARY_EVENT === packet.type || exports.BINARY_ACK === packet.type) { // binary packet's json
           this.reconstructor = new BinaryReconstructor(packet);
    
  • test/buffer.js+45 2 modified
    @@ -1,8 +1,7 @@
     var parser = require('../index.js');
     var expect = require('expect.js');
     var helpers = require('./helpers.js');
    -var encode = parser.encode;
    -var decode = parser.decode;
    +var Decoder = parser.Decoder;
     
     describe('parser', function() {
       it('encodes a Buffer', function() {
    @@ -14,6 +13,15 @@ describe('parser', function() {
           });
       });
     
    +  it("encodes a nested Buffer", function() {
    +    helpers.test_bin({
    +      type: parser.BINARY_EVENT,
    +      data: ["a", { b: ["c", Buffer.from("abc", "utf8")] }],
    +      id: 23,
    +      nsp: "/cool",
    +    });
    +  });
    +
       it('encodes a binary ack with Buffer', function() {
         helpers.test_bin({
           type: parser.BINARY_ACK,
    @@ -22,4 +30,39 @@ describe('parser', function() {
           nsp: '/back'
         })
       });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (string)", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":"splice"}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (out-of-bound)", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":1}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment without header", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^got binary data when not reconstructing a packet$/);
    +  });
    +
    +  it("throws an error when decoding a binary event without attachments", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":0}]');
    +      decoder.add('2["hello"]');
    +    }).to.throwException(/^got plaintext data when reconstructing a packet$/);
    +  });
     });
    
04d23cecafe1

fix: check the format of the index of each attachment

https://github.com/socketio/socket.io-parserDamien ArrachequesneNov 9, 2022via ghsa
3 files changed · +58 4
  • binary.js+10 2 modified
    @@ -70,8 +70,16 @@ exports.reconstructPacket = function(packet, buffers) {
     function _reconstructPacket(data, buffers) {
       if (!data) return data;
     
    -  if (data && data._placeholder) {
    -    return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +  if (data && data._placeholder === true) {
    +    var isIndexValid =
    +      typeof data.num === "number" &&
    +      data.num >= 0 &&
    +      data.num < buffers.length;
    +    if (isIndexValid) {
    +      return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +    } else {
    +      throw new Error("illegal attachments");
    +    }
       } else if (isArray(data)) {
         for (var i = 0; i < data.length; i++) {
           data[i] = _reconstructPacket(data[i], buffers);
    
  • index.js+3 0 modified
    @@ -239,6 +239,9 @@ Emitter(Decoder.prototype);
     Decoder.prototype.add = function(obj) {
       var packet;
       if (typeof obj === 'string') {
    +    if (this.reconstructor) {
    +      throw new Error("got plaintext data when reconstructing a packet");
    +    }
         packet = decodeString(obj);
         if (exports.BINARY_EVENT === packet.type || exports.BINARY_ACK === packet.type) { // binary packet's json
           this.reconstructor = new BinaryReconstructor(packet);
    
  • test/buffer.js+45 2 modified
    @@ -1,8 +1,7 @@
     var parser = require('../index.js');
     var expect = require('expect.js');
     var helpers = require('./helpers.js');
    -var encode = parser.encode;
    -var decode = parser.decode;
    +var Decoder = parser.Decoder;
     
     describe('parser', function() {
       it('encodes a Buffer', function() {
    @@ -14,6 +13,15 @@ describe('parser', function() {
           });
       });
     
    +  it("encodes a nested Buffer", function() {
    +    helpers.test_bin({
    +      type: parser.BINARY_EVENT,
    +      data: ["a", { b: ["c", Buffer.from("abc", "utf8")] }],
    +      id: 23,
    +      nsp: "/cool",
    +    });
    +  });
    +
       it('encodes a binary ack with Buffer', function() {
         helpers.test_bin({
           type: parser.BINARY_ACK,
    @@ -22,4 +30,39 @@ describe('parser', function() {
           nsp: '/back'
         })
       });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (string)", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":"splice"}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (out-of-bound)", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":1}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment without header", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^got binary data when not reconstructing a packet$/);
    +  });
    +
    +  it("throws an error when decoding a binary event without attachments", function() {
    +    var decoder = new Decoder();
    +
    +    expect(function() {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":0}]');
    +      decoder.add('2["hello"]');
    +    }).to.throwException(/^got plaintext data when reconstructing a packet$/);
    +  });
     });
    
b5d0cb7dc56a

fix: check the format of the index of each attachment

https://github.com/socketio/socket.io-parserDamien ArrachequesneJun 27, 2022via ghsa
4 files changed · +66 3
  • lib/binary.ts+10 2 modified
    @@ -60,8 +60,16 @@ export function reconstructPacket(packet, buffers) {
     function _reconstructPacket(data, buffers) {
       if (!data) return data;
     
    -  if (data && data._placeholder) {
    -    return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +  if (data && data._placeholder === true) {
    +    const isIndexValid =
    +      typeof data.num === "number" &&
    +      data.num >= 0 &&
    +      data.num < buffers.length;
    +    if (isIndexValid) {
    +      return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +    } else {
    +      throw new Error("illegal attachments");
    +    }
       } else if (Array.isArray(data)) {
         for (let i = 0; i < data.length; i++) {
           data[i] = _reconstructPacket(data[i], buffers);
    
  • lib/index.ts+3 0 modified
    @@ -145,6 +145,9 @@ export class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
       public add(obj: any) {
         let packet;
         if (typeof obj === "string") {
    +      if (this.reconstructor) {
    +        throw new Error("got plaintext data when reconstructing a packet");
    +      }
           packet = this.decodeString(obj);
           if (
             packet.type === PacketType.BINARY_EVENT ||
    
  • test/buffer.js+49 1 modified
    @@ -1,5 +1,6 @@
    -const { PacketType } = require("..");
    +const { PacketType, Decoder } = require("../");
     const helpers = require("./helpers.js");
    +const expect = require("expect.js");
     
     describe("parser", () => {
       it("encodes a Buffer", (done) => {
    @@ -14,6 +15,18 @@ describe("parser", () => {
         );
       });
     
    +  it("encodes a nested Buffer", (done) => {
    +    helpers.test_bin(
    +      {
    +        type: PacketType.EVENT,
    +        data: ["a", { b: ["c", Buffer.from("abc", "utf8")] }],
    +        id: 23,
    +        nsp: "/cool",
    +      },
    +      done
    +    );
    +  });
    +
       it("encodes a binary ack with Buffer", (done) => {
         helpers.test_bin(
           {
    @@ -25,4 +38,39 @@ describe("parser", () => {
           done
         );
       });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (string)", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":"splice"}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (out-of-bound)", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":1}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment without header", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^got binary data when not reconstructing a packet$/);
    +  });
    +
    +  it("throws an error when decoding a binary event without attachments", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":0}]');
    +      decoder.add('2["hello"]');
    +    }).to.throwException(/^got plaintext data when reconstructing a packet$/);
    +  });
     });
    
  • test/parser.js+4 0 modified
    @@ -146,5 +146,9 @@ describe("parser", () => {
         expect(() => new Decoder().add("999")).to.throwException(
           /^unknown packet type 9$/
         );
    +
    +    expect(() => new Decoder().add(999)).to.throwException(
    +      /^Unknown type: 999$/
    +    );
       });
     });
    
b559f050ee02

fix: check the format of the index of each attachment

https://github.com/socketio/socket.io-parserDamien ArrachequesneJun 27, 2022via ghsa
4 files changed · +66 3
  • lib/binary.ts+10 2 modified
    @@ -60,8 +60,16 @@ export function reconstructPacket(packet, buffers) {
     function _reconstructPacket(data, buffers) {
       if (!data) return data;
     
    -  if (data && data._placeholder) {
    -    return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +  if (data && data._placeholder === true) {
    +    const isIndexValid =
    +      typeof data.num === "number" &&
    +      data.num >= 0 &&
    +      data.num < buffers.length;
    +    if (isIndexValid) {
    +      return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    +    } else {
    +      throw new Error("illegal attachments");
    +    }
       } else if (Array.isArray(data)) {
         for (let i = 0; i < data.length; i++) {
           data[i] = _reconstructPacket(data[i], buffers);
    
  • lib/index.ts+3 0 modified
    @@ -129,6 +129,9 @@ export class Decoder extends Emitter {
       public add(obj: any) {
         let packet;
         if (typeof obj === "string") {
    +      if (this.reconstructor) {
    +        throw new Error("got plaintext data when reconstructing a packet");
    +      }
           packet = this.decodeString(obj);
           if (
             packet.type === PacketType.BINARY_EVENT ||
    
  • test/buffer.js+49 1 modified
    @@ -1,5 +1,6 @@
    -const { PacketType } = require("..");
    +const { PacketType, Decoder } = require("../");
     const helpers = require("./helpers.js");
    +const expect = require("expect.js");
     
     describe("parser", () => {
       it("encodes a Buffer", (done) => {
    @@ -14,6 +15,18 @@ describe("parser", () => {
         );
       });
     
    +  it("encodes a nested Buffer", (done) => {
    +    helpers.test_bin(
    +      {
    +        type: PacketType.EVENT,
    +        data: ["a", { b: ["c", Buffer.from("abc", "utf8")] }],
    +        id: 23,
    +        nsp: "/cool",
    +      },
    +      done
    +    );
    +  });
    +
       it("encodes a binary ack with Buffer", (done) => {
         helpers.test_bin(
           {
    @@ -25,4 +38,39 @@ describe("parser", () => {
           done
         );
       });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (string)", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":"splice"}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment with an invalid 'num' attribute (out-of-bound)", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":1}]');
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^illegal attachments$/);
    +  });
    +
    +  it("throws an error when adding an attachment without header", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add(Buffer.from("world"));
    +    }).to.throwException(/^got binary data when not reconstructing a packet$/);
    +  });
    +
    +  it("throws an error when decoding a binary event without attachments", () => {
    +    const decoder = new Decoder();
    +
    +    expect(() => {
    +      decoder.add('51-["hello",{"_placeholder":true,"num":0}]');
    +      decoder.add('2["hello"]');
    +    }).to.throwException(/^got plaintext data when reconstructing a packet$/);
    +  });
     });
    
  • test/parser.js+4 0 modified
    @@ -146,5 +146,9 @@ describe("parser", () => {
         expect(() => new Decoder().add("999")).to.throwException(
           /^unknown packet type 9$/
         );
    +
    +    expect(() => new Decoder().add(999)).to.throwException(
    +      /^Unknown type: 999$/
    +    );
       });
     });
    

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

10

News mentions

0

No linked articles in our index yet.