You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
inspector: SIGUSR1 should use next available port if 9922 is already used #16872
When having multiple node processes running in parallel, and sending SIGUSR1 to one of them the Inspector server started and binding in port 9222. When sending SIGUSR1 to another Node process, the Inspector server can't be started as port 9222 is already used.
Starting inspector on 127.0.0.1:9229 failed: address already in use
This limits debugging, and sending SIGUSR1 to a process should start the Inspector server on the next available port instead of failing. The used port could be outputted to stdout for detection.
I think you can use --inspect-port=<port> at startup, but this means you know the available port when process launches. If you did support dynamically assigning a random port, you've introduced a discovery problem; if you want to determine which port is assigned, then you need to parse that process's stdout.
Ideally, if dynamic port assignment on SIGUSR1 was supported, there'd be:
a startup flag to specify a range of debug ports to choose from.
a startup flag to specify that if the debugger is attached, then the port + pid should be written to some location.
This would probably work for most peoples' scenarios. For us, it would pose a few problems:
port chosen is not restricted to some range. Our runtime environment needs some network configuration, so knowing the port range up front is key. There may be some workarounds to this on our end that I need to investigate, but these would be significantly more complex.
I'm not keen to scan apps' stdout/stderr for the dynamically assigned port.
There were some discussions about giving programmatic control over the port selection (e.g. to allow user code/module to register a handler for the debug signal). Would this work for you?
@eugeneo we love the signaling mechanism to put a Node process into inspect mode.
Not sure if this would work, but here is a suggestion -
9229 (default port) continues to stay the default for the first time when anyone signals a node process. In addition to what is done currently, the current HTTP server will also provide a special endpoint to query ( say http://[host]:9229/json/listall) which anyone could query to get all inspector endpoints.
On the signalling side, whenever a process is signaled - SIGUSR1, Node would pick a new unused port and use that.
I guess node would have to find a way to fig. out random ports that are not being used. Doesn't it already do that today to check if 9229 is available?
There were some discussions about giving programmatic control over the port selection (e.g. to allow user code/module to register a handler for the debug signal). Would this work for you?
Not really, probably "too invasive" for our scenarios. So, we may have some work-arounds here that will be good enough. That said, if node runtime wanted to support dynamic port assignment, limited to a port range, and some reliable discovery mechanism, there'd be some switches like:
--inspect-port-range=1000:2000 // indicates the port range the debugger should choose from
--inspect-port-notification-directory=/some/path/ // indicates a path that node could write a file with name like pid-port.txt.
Then, a SIGUSR1 would pick one of those ports, drop a file in that location, and we can scan that directory to know which pid is listening on which port.
@bnoordhuis@mike-kaufman I understand the need for having a consistent discovery mechanism, and listening to strout on MacOS + Windows seems to be challenging, but I'd be hesitant of having Node writing to disk as assumes the Node process has I/O access, permissions, etc.
What are the alternatives? Emit port on a predefined POSIX signal?
Another thing that is in progress is subtargets - #16627
I think it should be possible for VSCode to run a "parrent" node and setup an inspector on it. Then it should be possible to send requests to start child nodes (once process.fork is supported for this scenario).
@dhanvikapila I do not see how this could be implemented, 9229 might be taken by "unrelated" Node process (e.g. ran by a different user) or some non-Node process.
Alternatively, if you're on a UNIX-like system, it's not too onerous to find out what ports the target process was listening on before and after signalling it. Worst case you shell out to lsof -p <pid>.
@eugeneo if my understanding is correct, event today if 9229 is unavailable, debugging will not work anyways since Node wont put the target process into inspect mode. Node cannot change this behavior without breaking backwards compatibility. I'm not claiming my proposal would be perfect but it provides a way forward when 9229 is available.
@bnoordhuislsof -p <pid> might work but we are trying to avoid parsing command output.
It should be possible to preallocate a port number if you have control over command-line options.
@eugeneo - that almost works. Issue here is if that pre-identified port is in-use when SIGUSR1 is received. Maybe we can get away with it, but my concern is at high enough scale it will show up.
Alternatively, if you're on a UNIX-like system, it's not too onerous to find out what ports the target process was listening on before and after signalling it. Worst case you shell out to
@bnoordhuis - yeah, that almost works too. Issue here is if node process opens an additional port between your SIGUSR1 and your lsof .... Maybe so unlikely that it will never occur, but again, at high enough scale, it will impact some people.
but I'd be hesitant of having Node writing to disk as assumes the Node process has I/O access, permissions, etc.
@auchenberg - I think it's safe to assume that if you specify a directory on command-line, there's perms sufficient to write to it.
looks like the discussion has identified a couple of viable workarounds for the reported problem (pre-allocating ports, discovery using lsof). Are we good to close this?
Ran across this issue again myself, trying to have SIGUSR1 open the inspector on child processes when the default 9229 was already in use by parents and/or other some other process. This is my solution:
Pretty simple npm package that you can simply require('fiveo'), start your new process with INSPECT=9230 (or whatever [host:port]), done!
You can also use it without the INSPECT env and it will default to localhost:9229.
Please never 'fix' this. The existence of this 'feature', and no decent way to globally disable it, is already a major PITA from a security perspective, if not a plain vulnerability. One, and possibly the only, way to disable inspector attacks machine wide is exactly to make sure that something else is already listening on port 9229 so that when an attacker would manage to send SIGUSR1 to any running node process it could not open the inspector port.
This is not a security vulnerability. Your system is already compromised if the attacker can send a signal to arbitrary process.
When an attacker manages to compromise a system to some level it would be great if what they can do from that position is reduced to an absolute minimum. This is a main focus of several common cyber security best practices (such as anything related to access control). A gateway that lets you inspect and manipulate the entire internal state of programs (which could potentially play a critical role in that access control) makes this very hard.
Hardening IT systems is not only about keeping external attackers out. It's also about making sure that abilities of internal actors limited to the minimum possible. IE the operations guy should usually be able to do things such as stopping/starting services but definitely not things such as extracting (potentially sensitive customer) data from or changing functionality of those services. Not being able to globally disable a debugging interface, again, makes this very hard to enforce.
I'm sure many more examples of how a debugging interface that can not globally/permanently be disabled works directly against good security practices can be thought of.
Is a feature that could (easily) be exploited to (further) compromise a systems security and can not be globally/permanently disabled a vulnerability per se? Debatable perhaps. But I would say that it should definitely be under careful consideration.
Activity
auchenberg commentedon Nov 7, 2017
(cc @joshgav @mike-kaufman @ofrobots)
mike-kaufman commentedon Nov 7, 2017
I think you can use
--inspect-port=<port>at startup, but this means you know the available port when process launches. If you did support dynamically assigning a random port, you've introduced a discovery problem; if you want to determine which port is assigned, then you need to parse that process's stdout.Ideally, if dynamic port assignment on
SIGUSR1was supported, there'd be:bnoordhuis commentedon Nov 16, 2017
@auchenberg Does
--inspect-port=0work for you? You can capture the address and port on stderr.auchenberg commentedon Nov 16, 2017
@bnoordhuis I wasn't aware that
--inspect-port=0existed for dynamic port assignment. What do you think @mike-kaufman?mike-kaufman commentedon Nov 16, 2017
This would probably work for most peoples' scenarios. For us, it would pose a few problems:
port chosen is not restricted to some range. Our runtime environment needs some network configuration, so knowing the port range up front is key. There may be some workarounds to this on our end that I need to investigate, but these would be significantly more complex.
I'm not keen to scan apps' stdout/stderr for the dynamically assigned port.
bnoordhuis commentedon Nov 17, 2017
You'd have to do that with @auchenberg's proposed scheme too, right?
eugeneo commentedon Nov 17, 2017
There were some discussions about giving programmatic control over the port selection (e.g. to allow user code/module to register a handler for the debug signal). Would this work for you?
dhanvikapila commentedon Nov 17, 2017
@eugeneo we love the signaling mechanism to put a Node process into inspect mode.
Not sure if this would work, but here is a suggestion -
9229 (default port) continues to stay the default for the first time when anyone signals a node process. In addition to what is done currently, the current HTTP server will also provide a special endpoint to query ( say http://[host]:9229/json/listall) which anyone could query to get all inspector endpoints.
On the signalling side, whenever a process is signaled - SIGUSR1, Node would pick a new unused port and use that.
I guess node would have to find a way to fig. out random ports that are not being used. Doesn't it already do that today to check if 9229 is available?
mike-kaufman commentedon Nov 17, 2017
Not really, probably "too invasive" for our scenarios. So, we may have some work-arounds here that will be good enough. That said, if node runtime wanted to support dynamic port assignment, limited to a port range, and some reliable discovery mechanism, there'd be some switches like:
--inspect-port-range=1000:2000// indicates the port range the debugger should choose from--inspect-port-notification-directory=/some/path/// indicates a path that node could write a file with name like pid-port.txt.Then, a
SIGUSR1would pick one of those ports, drop a file in that location, and we can scan that directory to know which pid is listening on which port.auchenberg commentedon Nov 17, 2017
@bnoordhuis @mike-kaufman I understand the need for having a consistent discovery mechanism, and listening to
strouton MacOS + Windows seems to be challenging, but I'd be hesitant of having Node writing to disk as assumes the Node process has I/O access, permissions, etc.What are the alternatives? Emit port on a predefined POSIX signal?
eugeneo commentedon Nov 17, 2017
Another thing that is in progress is subtargets - #16627
I think it should be possible for VSCode to run a "parrent" node and setup an inspector on it. Then it should be possible to send requests to start child nodes (once process.fork is supported for this scenario).
eugeneo commentedon Nov 17, 2017
@dhanvikapila I do not see how this could be implemented, 9229 might be taken by "unrelated" Node process (e.g. ran by a different user) or some non-Node process.
@auchenberg
There is a requirement for inspector-over-pipe. It would likely look something like -inspector-pipe=/path/to/pipe.
@mike-kaufman
It should be possible to preallocate a port number if you have control over command-line options.
bnoordhuis commentedon Nov 17, 2017
Alternatively, if you're on a UNIX-like system, it's not too onerous to find out what ports the target process was listening on before and after signalling it. Worst case you shell out to
lsof -p <pid>.dhanvikapila commentedon Nov 17, 2017
@eugeneo if my understanding is correct, event today if 9229 is unavailable, debugging will not work anyways since Node wont put the target process into inspect mode. Node cannot change this behavior without breaking backwards compatibility. I'm not claiming my proposal would be perfect but it provides a way forward when 9229 is available.
@bnoordhuis
lsof -p <pid>might work but we are trying to avoid parsing command output.mike-kaufman commentedon Nov 17, 2017
@eugeneo - that almost works. Issue here is if that pre-identified port is in-use when SIGUSR1 is received. Maybe we can get away with it, but my concern is at high enough scale it will show up.
@bnoordhuis - yeah, that almost works too. Issue here is if node process opens an additional port between your
SIGUSR1and yourlsof .... Maybe so unlikely that it will never occur, but again, at high enough scale, it will impact some people.@auchenberg - I think it's safe to assume that if you specify a directory on command-line, there's perms sufficient to write to it.
gireeshpunathil commentedon May 16, 2018
looks like the discussion has identified a couple of viable workarounds for the reported problem (pre-allocating ports, discovery using
lsof). Are we good to close this?bnoordhuis commentedon Feb 8, 2019
Since this issue hasn't seen any action in over a year I'm going to go ahead and close it out. Please reopen if necessary.
june07 commentedon Aug 20, 2019
Ran across this issue again myself, trying to have SIGUSR1 open the inspector on child processes when the default 9229 was already in use by parents and/or other some other process. This is my solution:

Pretty simple npm package that you can simply
require('fiveo'), start your new process with INSPECT=9230 (or whatever [host:port]), done!You can also use it without the INSPECT env and it will default to localhost:9229.
https://www.npmjs.com/package/fiveo
dreusel commentedon Jun 5, 2025
Please never 'fix' this. The existence of this 'feature', and no decent way to globally disable it, is already a major PITA from a security perspective, if not a plain vulnerability. One, and possibly the only, way to disable inspector attacks machine wide is exactly to make sure that something else is already listening on port 9229 so that when an attacker would manage to send SIGUSR1 to any running node process it could not open the inspector port.
eugeneo commentedon Jun 5, 2025
This is not a security vulnerability. Your system is already compromised if the attacker can send a signal to arbitrary process.
dreusel commentedon Jun 6, 2025
@eugeneo
I'm sure many more examples of how a debugging interface that can not globally/permanently be disabled works directly against good security practices can be thought of.
Is a feature that could (easily) be exploited to (further) compromise a systems security and can not be globally/permanently disabled a vulnerability per se? Debatable perhaps. But I would say that it should definitely be under careful consideration.