Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/pentesting-web/dependency-confusion.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,34 @@ 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.

### Related pattern: `npx` binary/package-name confusion

`npx <name>` is also a **name-confusion execution sink**. If no explicit `--package` is provided, npm first tries to resolve `<name>` as a binary from the local `node_modules/.bin`, global bins, local/global installed packages, and the npx cache. If none of those checks succeed, npm treats the original binary name as the package name, installs it into `~/.npm/_npx/<hash>/`, prepends that cache's `node_modules/.bin` to `PATH`, and executes it. In CI or non-TTY contexts, npm assumes `--yes`, so the install path is even easier to reach automatically.

Why this is exploitable:
- **Binary names and package names do not need to match.** A command may be `binary_name` while the real package is `@company/package-name`.
- **Scoped/private packages increase the gap.** The package can be scoped, but the exposed `bin` name is unscoped.
- **Exploitability is context-dependent.** `npx binary_name` may be safe inside the project root where the real binary exists, but unsafe in CI, in a clean workspace, outside the repo root, or in agent automation where `node_modules/.bin` is absent.

Typical recon sources:
- `package.json` scripts containing `npx <binary>`
- READMEs and onboarding docs
- CI/CD workflows
- bundled manifests leaked in frontend assets
- AI-agent tool definitions that shell out through `npx`

Practical abuse pattern:
1. Find `npx <binary_name>` where the intended tool actually comes from another package.
2. Check whether `<binary_name>` exists as a public npm package.
3. If the public name is unclaimed, register it and expose the expected command via the package `bin` field.
4. Wait for execution in a context where the legitimate local binary is missing; npm will fetch the attacker-controlled package into `~/.npm/_npx/` and run it.

Defensive notes specific to this pattern:
- Prefer **explicit package resolution**: `npx --package=@company/package-name binary_name` or `npm exec --package=@company/package-name -- binary_name`.
- Claim public npm names that match internal/private binaries, especially for scoped packages.
- Treat CI/non-TTY warnings about missing packages that "will be installed" as security events.
- Monitor unexpected cache installs under `~/.npm/_npx/`.

### 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.
Expand Down Expand Up @@ -384,6 +412,10 @@ These controls do **not** replace lockfiles or trusted publishing, but they redu
- [https://docs.npmjs.com/trusted-publishers/](https://docs.npmjs.com/trusted-publishers/)
- [https://docs.npmjs.com/generating-provenance-statements](https://docs.npmjs.com/generating-provenance-statements)
- [https://docs.npmjs.com/cli/v11/using-npm/changelog/](https://docs.npmjs.com/cli/v11/using-npm/changelog/)
- [npm exec | npm Docs](https://docs.npmjs.com/cli/v11/commands/npm-exec/)
- [npm/cli v11.15.0 libnpmexec index.js](https://github.com/npm/cli/blob/v11.15.0/workspaces/libnpmexec/lib/index.js)
- [npm/cli v11.15.0 file-exists.js](https://github.com/npm/cli/blob/v11.15.0/workspaces/libnpmexec/lib/file-exists.js)
- [npx Used Confusion and It’s Super Effective](https://www.landh.tech//blog/20260521-npx-used-confusion-and-its-super-effective)
- [https://pnpm.io/settings](https://pnpm.io/settings)
- [https://bun.sh/docs/runtime/bunfig](https://bun.sh/docs/runtime/bunfig)

Expand Down