What is dependency confusion? (and typosquatting)
Dependency confusion exploits how package managers resolve names: if your build references an internal package name that also exists on a public registry, the resolver can be tricked into fetching the attacker's public version instead of your private one. Typosquatting is the related trick of registering names that look like popular packages to catch typos. Both defend against the same way: control name resolution, and inventory what you actually pulled.
Dependency confusion is a supply chain attack that abuses something mundane: how package managers decide which package a name refers to. It turns your build’s own resolution logic into the delivery mechanism, which is what makes it both elegant and dangerous. Alongside its cousin typosquatting, it is one of the most reliable ways to get malicious code executed inside a target’s build - not by breaking in, but by being helpfully installed.
How dependency confusion works
The attack has a simple shape:
- Your organization uses internal packages with private names, referenced in your builds and resolved from an internal source.
- An attacker learns one of those names - they leak constantly, in committed config files, error messages, and public build logs.
- The attacker publishes a package with that exact name on a public registry, at a very high version number.
- Your build resolver, configured to consider the public registry and to prefer the highest version, fetches the attacker’s package instead of your internal one - and package installs routinely execute code, so the malicious payload runs inside your pipeline.
The victim did nothing unusual. The resolver behaved exactly as designed. That is the danger: the attack lives in a default, not in a mistake.
Typosquatting, the related trick
Typosquatting targets human error rather than resolver logic. The attacker registers malicious packages under names that closely resemble popular ones - a transposed letter, a dropped character, a plausible variant - and waits for a developer’s typo or a mistaken copy-paste to install it. Different mechanism, same outcome: an unintended, malicious package in your dependency tree, executing on install.
Both are members of the broader family of software supply chain attacks, and both exploit the trust builds place in package names.
Defending against both
The defenses share a root: do not let a name resolve to something you did not intend.
- Control name resolution. Ensure internal names always resolve to your internal source and can never be satisfied by a public registry - through scoped namespaces, explicit and pinned registry configuration, or an internal mirror that is authoritative for your names. This closes the confusion path directly.
- Pin and verify. Lockfiles with integrity hashes ensure you get the exact artifact you approved, not merely a name-and-version match, which blunts both attacks.
- Inventory what was actually pulled. A complete dependency inventory generated from the real resolution - not from the manifest’s intent - reveals when the thing installed is not the thing you meant to install. This is where an accurate SBOM earns its keep as a detection tool, not just a compliance artifact.
The airgap-native version of the resolution defense is worth noting: when your builds resolve against your own internal mirror rather than the public internet, the public-registry confusion vector is closed by architecture. SecuDep supports exactly this - resolving no-lockfile dependencies against your own registry mirror - so that name resolution stays inside your control, and its extraction records what was truly pulled so a substitution cannot hide in the inventory.
Frequently asked questions
How does dependency confusion actually work?
An attacker learns the name of one of your internal packages - often leaked in a config file or an error message - and publishes a package with that same name, at a high version number, on a public registry. If your build resolver checks the public registry and picks the highest version, it pulls the attacker's code instead of your internal package, and executes it during install.
How is typosquatting different?
Typosquatting registers malicious packages under names that resemble popular ones - a transposed letter, a missing hyphen - so that a developer's typo, or a copy-paste error, installs the malicious package. Dependency confusion targets your private names; typosquatting targets your fingers. Both end with a malicious package in your build.
What is the primary defense?
Controlling name resolution so internal names always resolve to your internal source, never to a public registry - through scoped namespaces, explicit registry configuration, or an internal mirror that is authoritative for your names. Backing that with an inventory of what was actually resolved catches anything that slips through.