[DevTools Bug]: standalone startServer ignores the host argument and listens beyond loopback
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.
Create an empty directory and install the current packages used by this reproduction:
npm init -y npm install [email protected] [email protected]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);Run:
node bind-check.cjsAlthough
startServer()was explicitly called with127.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)
Source: facebook/react