Skip to content

I don’t see an alternative: “DeprecationWarning: Passing args to a child process with shell option true …” #5063

Closed

Description

@rauschma

Node.js Version

v24.0.1

NPM Version

11.3.0

Operating System

macOS Sequoia 15.3.2

Subsystem

child_process

Description

When using child_process.spawnSync() with an Array of arguments, I’m getting this warning:

DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.

I don’t see a simple way around that:

  • Command and arguments are passed to my function as an Array.
  • I can do my own concatenation but how is that any better than what Node.js is doing?
  • If I set shell:false then, e.g., I can’t invoke npx <some-package>.

Minimal Reproduction

No response

Output

No response

Before You Submit

  • I have looked for issues that already exist before submitting this
  • My issue follows the guidelines in the README file, and follows the 'How to ask a good question' guide at https://stackoverflow.com/help/how-to-ask

Activity

  1. avivkeller commented on May 15, 2025

    @avivkeller
    Member

    The deprecation is https://nodejs.org/api/deprecations.html#DEP0190, so you can disable it with --disable-warning=DEP0190

    But, if you show your code, we can see why the deprecation is occurring you do can make the code future proof.

  2. avivkeller commented on May 22, 2025

    @avivkeller
    Member

    Hey, did the answer above resolve your problem? If not, can you provide more information?

  3. added
    answered🎉 Yay! The issue has been resolved, or the question has been answered.
    on May 22, 2025
  4. rauschma commented on May 22, 2025

    @rauschma
    Author

    Ah, I only just now saw the second line of your initial reply. Alas, that doesn’t help me.

    My input:

    ["npx", "ts-expect-error", "--unexpected-errors", "main.ts"]
    • I want to run that as a shell command. Needed in the following project (which creates files and calls external tools with them): https://github.com/rauschma/markcheck
    • I wouldn’t want to suppress warnings. If there is no other solution, I’d create a single-string shell command myself. But, as mentioned, that’s not safer than what Node.js does.
  5. removed
    answered🎉 Yay! The issue has been resolved, or the question has been answered.
    needs more infoissues that need more info from the author
    on May 22, 2025
  6. joshualip-plaudit commented on May 31, 2025

    @joshualip-plaudit

    As a follow-on to this, because you cannot set stdio on exec, there isn't an alternative to passing args to spawn.

  7. lifeisfoo commented on Jun 7, 2025

    @lifeisfoo

    Another example when shell: true is required is to enable file globbing from the shell.

    spawn("ls", ["*.mjs"], { shell: true });
    

    Any workaround for this?

  8. alcuadrado commented on Jun 18, 2025

    @alcuadrado

    I believe the alternative would be to pass the entire command to spawn. Like

    spawn("ls *.mjs", { shell: true });

    in the example above

  9. trevorstr commented on Jun 26, 2025

    @trevorstr

    I just started getting this warning, and I am not sure why. I am not using spawn() anywhere in my code.

    Maybe one of the dependencies in my project is using it, but I'm not sure how I would go about figuring that out. How do I know what line is triggering the deprecation warning?

  10. trevorstr commented on Jun 26, 2025

    @trevorstr

    I just noticed the warning mentions the --trace-deprecation option. :)

  11. trevorstr commented on Jun 26, 2025

    @trevorstr

    So in my scenario, I am using various modules from the Azure SDK. One class I'm using in particular is the AzureCliCredential class. It appears that this module is calling an external process, using the deprecated functionality.

    ../node_modules/@azure/identity/dist/commonjs/credentials/azureCliCredential.js:53:41
    

    I'm currently using @azure/identity version 4.8.0.

  12. adligo commented on Jul 1, 2025

    @adligo

    As far as I can tell, the solution with the concatenated string as the command doesn't work for me in my slink.ts.adligo.org project, as it sets the statusCode (status) to null when it should be zero. I need the statusCode (status) to be zero in order to tell if the command executed successfully!

        if (spawnSyncReturns.status != 0) {
          throw new Error('The command ' + cmdWithArgs + ' in dir \n\t' + options.cwd + ' \n\t Failed with exit code: ' + spawnSyncReturns.status);
        }
    

    I'm adding a separate bug report for this.

  13. 18 remaining items

  14. aleclarson commented on Aug 21, 2025

    @aleclarson

    From https://github.com/xxorax/node-shell-escape/blob/master/shell-escape.js

    function shellescape(a) {
      var ret = [];
    
      a.forEach(function(s) {
        if (/[^A-Za-z0-9_\/:=-]/.test(s)) {
          s = "'"+s.replace(/'/g,"'\\''")+"'";
          s = s.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning
            .replace(/\\'''/g, "\\'" ); // remove non-escaped single-quote if there are enclosed between 2 escaped
        }
        ret.push(s);
      });
    
      return ret.join(' ');
    }

    MIT license

  15. nex3 commented on Oct 31, 2025

    @nex3

    It's also worth noting that the messaging for CVE-2024-27980 suggests passing { shell: true } without saying anything about needing to pass arguments differently.

  16. adligo commented on Jan 19, 2026

    @adligo

    I eventually partially fixed this in my slink project by updating the shim to pass this in directly from;

    #!/bin/sh
    basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
    
    case `uname` in
        *CYGWIN*|*MINGW*|*MSYS*)
            if command -v cygpath > /dev/null 2>&1; then
                basedir=`cygpath -w "$basedir"`
            fi
        ;;
    esac
    
    if [ -x "$basedir/node" ]; then
      exec "$basedir/node"  "$basedir/node_modules/@ts.adligo.org/slink/dist/slink.mjs" "$@"
    else
      exec node "$basedir/node_modules/@ts.adligo.org/slink/dist/slink.mjs" "$@"
    fi
    

    to

    #!/bin/sh
    basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
    
    case `uname` in
        *CYGWIN*|*MINGW*|*MSYS*)
            if command -v cygpath > /dev/null 2>&1; then
                basedir=`cygpath -w "$basedir"`
            fi
        ;;
    esac
    
    if [ -x "$basedir/node" ]; then
      exec "$basedir/node"  "--disable-warning=DEP0190"  "$basedir/node_modules/@ts.adligo.org/slink/dist/slink.mjs" "$@"
    else
      exec node --disable-warning=DEP0190 "$basedir/node_modules/@ts.adligo.org/slink/dist/slink.mjs" "$@"
    fi
    

    Although this means I can no longer use npmjs.com to install the program. as I have a hack in my local installation script to do;
    build.cjs ...
    run('cp', ['src/slink.sh', 'which slink'], options);

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions