#37624·React

[DevTools Bug]: standalone startServer ignores the host argument and listens beyond loopback

Author: taxor03Created Sep 14, 2026Updated Sep 16, 2026
LabelsType: BugStatus: UnconfirmedComponent: Developer Tools

Website or app

React DevTools standalone package: https://github.com/react/react/tree/main/packages/react-devtools

Repro steps

[email protected] passes its configured host to react-devtools-core/standalone.startServer(port, host). The default host is documented as localhost, but the supplied value is not applied to the HTTP listening socket.

  1. Create an empty directory and install the current packages used by this reproduction:

    npm init -y
    npm install [email protected] [email protected]
    
  2. Save the following as bind-check.cjs:

    'use strict';
    
    const { JSDOM, VirtualConsole } = require('jsdom');
    const net = require('node:net');
    const os = require('node:os');
    
    const dom = new JSDOM('<!doctype html><body></body>', {
      pretendToBeVisual: true,
      url: 'http://localhost',
      virtualConsole: new VirtualConsole(),
    });
    dom.window.ResizeObserver = class {
      observe() {}
      unobserve() {}
      disconnect() {}
    };
    
    for (const key of [
      'window',
      'document',
      'navigator',
      'HTMLElement',
      'Element',
      'Node',
      'localStorage',
      'sessionStorage',
    ]) {
      global[key] = key === 'window'
        ? dom.window
        : key === 'document'
          ? dom.window.document
          : dom.window[key];
    }
    global.getComputedStyle = dom.window.getComputedStyle.bind(dom.window);
    global.requestAnimationFrame = dom.window.requestAnimationFrame.bind(dom.window);
    global.cancelAnimationFrame = dom.window.cancelAnimationFrame.bind(dom.window);
    
    const nonLoopback = Object.values(os.networkInterfaces())
      .flat()
      .filter(Boolean)
      .find(entry => entry.family === 'IPv4' && !entry.internal);
    if (!nonLoopback) throw new Error('No non-loopback IPv4 address found');
    
    const DevTools = require('react-devtools-core/standalone').default;
    DevTools.setContentDOMNode(document.body);
    
    const port = 18098;
    const requestedHost = '127.0.0.1';
    const server = DevTools.startServer(port, requestedHost);
    
    function finish(code) {
      server.close();
      setTimeout(() => process.exit(code), 50);
    }
    
    setTimeout(() => {
      const socket = net.connect(port, nonLoopback.address);
      socket.on('connect', () => {
        console.log(JSON.stringify({
          requestedHost,
          connectedVia: nonLoopback.address,
        }));
        socket.destroy();
        finish(0);
      });
      socket.on('error', error => {
        console.error(error);
        finish(1);
      });
    }, 100);
    
    setTimeout(() => finish(2), 5000);
    
  3. Run:

    node bind-check.cjs
    
  4. Although startServer() was explicitly called with 127.0.0.1, the connection through the same machine's non-loopback address succeeds:

    {"requestedHost":"127.0.0.1","connectedVia":"<non-loopback IPv4>"}
    

The test makes only a local connection to the same machine.

Expected: passing 127.0.0.1 or localhost restricts the listening socket to that host, as described by the API and standalone documentation.

Actual: the implementation calls httpServer.listen(port) without the supplied host, so Node listens on an unspecified address.

A direct fix would be to forward the argument:

httpServer.listen(port, host, callback)

Environment used: macOS, Node.js 20.19.5.

How often does this bug happen?

Every time

DevTools package (automated)

No response

DevTools version (automated)

No response

Error message (automated)

No response

Error call stack (automated)

Error component stack (automated)

GitHub query string (automated)