Dependency Confusion
Dependency confusion exploits package managers that prefer a public package over a private one with the same name, letting an attacker publish a malicious higher version.
Definition
Dependency confusion is a supply-chain attack in which an adversary publishes a public package whose name matches an internal dependency, hoping the build resolver selects the public version because it is newer or because registry precedence is misconfigured.
Context and scope
Use this concept when reviewing private package feeds, scoped names, lockfiles, and CI install steps, especially in organizations that mix internal and public registries.
Common misconceptions
- Private registries are immune; misconfigured fallback to public registries recreates the risk
- Version pinning alone prevents it; a lockfile refresh can still resolve to the public package
- Only npm is affected; pip, Maven, NuGet, and Gem ecosystems have equivalent behaviors
Anti-patterns
- Using unscoped internal names that could exist on the public registry
- Configuring a public registry as a fallback for every package
- Running installs with scripts enabled and no dependency review in CI
Related concepts
Related examples
Authoritative source
https://cheatsheetseries.owasp.org/cheatsheets/Software_Supply_Chain_Security_Cheat_Sheet.html
The resolver decides
Package managers resolve a name to a version across one or more registries. If a private package named acme-utils lives internally and an attacker publishes [email protected] publicly, a resolver that checks both sources may pick the higher public version. The build installs attacker code with the organization’s privileges.
How it works
The attacker first learns internal package names from leaked manifests, public CI logs, job postings, or error messages. They publish a package with the same name and a very high version, sometimes including a preinstall script that exfiltrates environment variables or tokens. The build system, treating the public registry as authoritative for unscoped names, pulls it in.
Defenses work at several layers: use scoped names such as @acme/utils and map the scope to the private registry only, disable public fallback for internal scopes, commit lockfiles with integrity hashes, and run npm ci rather than a resolving install. A proxy registry that blocks unknown packages and requires approval adds another barrier.
When to use it
Apply these controls in every repository that publishes or consumes internal packages. They matter most in CI, where tokens and deployment credentials are present. Open-source maintainers should reserve their package names on public registries even if distribution is private.
Trade-offs
Scoping is effective but requires renaming and migration. Blocking public fallback can break builds that genuinely need a public package, so exceptions need review. Lockfiles help but are only as good as the review process that updates them. Private proxies add infrastructure but give visibility and a kill switch.
Example and misconceptions
A company builds an internal telemetry-agent. An attacker publishes the same name publicly at version 99 with a postinstall script. A build with public fallback installs it and sends CI secrets to an external host.
The common misconception is that private code is invisible. Names leak constantly, and the attack does not require access to the private registry at all.
Related concepts: Supply Chain Security, Dependency Pinning, and Typosquatting.