A Node CLI that shells out to npm-installed tools on Windows starts printing this on every single spawn once the runtime is recent enough:
[DEP0190] DeprecationWarning: Passing args to a child process with shell option true
can lead to security vulnerabilities, as the arguments are not escaped.
It shows up whether the child succeeds or fails, and it is not a problem with the child. It is Node warning that the calling convention you are using will change (pingdotgg/t3code#19385).
Why it happens
When shell: true, Node joins [file, ...args] with spaces and hands the result to cmd.exe /d /s /c "<line>". The args array is the problem: Node is telling you that this implicit joining is not escaped properly and will eventually stop working. The warning fires whenever both shell: true and a non-empty args array are present:
// warns on every call
spawn('npm.cmd', ['install'], { shell: true })
The fix
Escape the path and each argument yourself, join them into one command string, and pass an empty args array. Node only warns when args are present, so the warning stops and the command line is byte-identical to what Node would have built:
const line = [file, ...args].map(escapeForCmd).join(' ')
spawn(line, [], { shell: true })
Use the same escaping rules as cross-spawn for spaces, quotes, %VAR%, carets, pipes, redirects, and trailing backslashes. On Node 24, spawn(line, [], { shell: true }) prints no DEP0190 while spawn(file, args, { shell: true }) does.
One gotcha if you switch to spawning cmd.exe /c directly instead: you need windowsVerbatimArguments threaded through every caller, otherwise Node re-quotes the /c line and breaks paths with spaces.