Skip to content

[engine.io-client] The client writes the URI into the options object, so a reused object sends one URL's query to the next server #5597

Open

Description

@adityajai119

Describe the bug

The client writes the parts of the URI into the options object passed to it: the Socket constructor of engine.io-client sets hostname, secure, port and query on it, and io() in socket.io-client also sets path and query. When the same options object is used for another connection, the query string of the first URI (for example a token) is sent to the second server.

To Reproduce

Socket.IO server version: 4.8.4

Server

const { createServer } = require("node:http");
const { Server } = require("socket.io");

for (const port of [3000, 3001]) {
  const httpServer = createServer();
  const io = new Server(httpServer);

  io.on("connection", (socket) => {
    console.log(`server on port ${port} received token:`, socket.handshake.query.token);
  });

  httpServer.listen(port);
}

Socket.IO client version: 4.8.4 (engine.io-client 6.6.8, also reproduced on main at 545e984)

Client

const { io } = require("socket.io-client");

const opts = { transports: ["websocket"] };

const a = io("http://localhost:3000/?token=secret-for-3000", opts);

a.on("connect", () => {
  const b = io("http://localhost:3001/", opts);
});

Server output:

server on port 3000 received token: secret-for-3000
server on port 3001 received token: secret-for-3000

The same happens with engine.io-client alone (new Socket("ws://localhost:3000/?token=secret-for-3000", opts), then new Socket("ws://localhost:3001/", opts)). After the first call, opts is:

{
  transports: [ 'websocket' ],
  hostname: 'localhost',
  secure: false,
  port: '3000',
  query: 'token=secret-for-3000'
}

Expected behavior

The options object is left as it was, and each connection only sends the query of its own URI:

server on port 3000 received token: secret-for-3000
server on port 3001 received token: undefined

Platform:

  • Device: desktop
  • OS: Windows, Node.js 24.22.1

Additional context

#5462 fixed the transports part of the same pattern. The remaining writes are in the constructor of Socket in packages/engine.io-client/lib/socket.ts, and in lookup() in packages/socket.io-client/lib/index.ts (opts.query = parsed.queryKey, plus opts.path set by the Manager). I'm opening a PR with a fix and tests.

AI-assisted: found and reproduced with an AI coding agent; the example above was run locally.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions