diff --git a/src/pentesting-web/dependency-confusion.md b/src/pentesting-web/dependency-confusion.md index 34b5903fcb6..2df62a5f17e 100644 --- a/src/pentesting-web/dependency-confusion.md +++ b/src/pentesting-web/dependency-confusion.md @@ -28,6 +28,33 @@ If your project references a library that isn’t available in the private regis Developers frequently leave versions unpinned or allow wide ranges. When a resolver is configured with both internal and public indexes, it may select the newest version regardless of source. For internal names like `requests-company`, if the internal index has `1.0.1` but an attacker publishes `1.0.2` to the public registry and your resolver considers both, the public package may win. +### npx binary/package-name confusion + +`npx ` / `npm exec -- ` can become a **supply-chain execution primitive** even when there is no private-vs-public registry precedence issue. If no `--package` option is given, npm first tries to resolve `` as a local/global executable; if it cannot, it may **reinterpret the unresolved binary name as the package name**, install it from the public registry into `~/.npm/_npx//`, prepend that cache's `node_modules/.bin` to `PATH`, and execute it. + +Why this matters: +- The public package name does **not** need to match the original internal package name. It only needs to match the **binary** invoked via `npx`. +- Scoped packages such as `@company/toolkit` commonly expose an unscoped `bin` name such as `toolkit-cli`, creating a natural mismatch between package name and executable name. +- The bug triggers when the expected binary is missing from the current context (wrong directory, missing `node_modules`, CI job without dependencies, fresh workstation, or an autonomous agent running commands outside the project root). + +Typical flow to abuse: +1. Find `npx binary_name` in exposed `package.json`, CI YAML, docs, shell scripts, or AI-agent tooling. +2. Check whether the public npm package `binary_name` is unclaimed. +3. Register/publish that package with a matching `bin` entry. +4. Wait for a victim environment to run `npx binary_name` where the intended local executable is unavailable. +5. npm installs the attacker-controlled package in `~/.npm/_npx/` and executes the exported binary. + +Technical notes: +- npm documents that when no `--package` option is provided, it infers the package/executable from the first positional argument; using `--package` disables that inference. +- In `npm/cli` `v11.15.0`, the `libnpmexec` path pushes the unresolved first argument into the package list (`packages.push(args[0])`) before later cache installation/re-execution. +- In non-interactive environments or CI, npm assumes approval and installs missing packages into the cache automatically. + +Hunting / hardening tips: +- Grep for `npx ` in repos, CI pipelines, generated bundles, and docs; review every invocation that does **not** use `--package`. +- Prefer explicit forms such as `npx --package=@company/toolkit toolkit-cli` or direct `./node_modules/.bin/toolkit-cli` execution in automation. +- Reserve public npm names matching internal binary names exposed by scoped/private packages. +- Treat AI agents and build runners as high-risk amplifiers because they may execute `npx` automatically and repeatedly. + ### Related pattern: compromise of a legitimate package release Dependency confusion is not the only way to get install-time execution. If an attacker compromises the maintainer account or publishing token of a legitimate package, they can publish a malicious version of the real package and obtain code execution on every machine that installs it. @@ -386,6 +413,9 @@ These controls do **not** replace lockfiles or trusted publishing, but they redu - [https://docs.npmjs.com/cli/v11/using-npm/changelog/](https://docs.npmjs.com/cli/v11/using-npm/changelog/) - [https://pnpm.io/settings](https://pnpm.io/settings) - [https://bun.sh/docs/runtime/bunfig](https://bun.sh/docs/runtime/bunfig) +- [https://www.landh.tech/blog/20260521-npx-used-confusion-and-its-super-effective](https://www.landh.tech/blog/20260521-npx-used-confusion-and-its-super-effective) +- [https://docs.npmjs.com/cli/v11/commands/npm-exec/](https://docs.npmjs.com/cli/v11/commands/npm-exec/) +- [https://github.com/npm/cli/blob/v11.15.0/workspaces/libnpmexec/lib/index.js](https://github.com/npm/cli/blob/v11.15.0/workspaces/libnpmexec/lib/index.js) {{#include ../banners/hacktricks-training.md}}