Free — no signup required

Dependency Confusion Attacks

2 min read

The "Internal" Namespace Exploit

In 2021, security researcher Alex Birsan published a technique that allowed him to execute code inside the internal networks of Apple, Microsoft, PayPal, Tesla, Uber, and dozens of other companies — without exploiting any vulnerability in their code. He exploited the resolution logic of package managers.

The Setup:

  1. A company has an internal private library named mycompany-auth hosted on their private Artifactory instance.
  2. Their package.json lists "mycompany-auth": "^1.0.0".
  3. Their build servers are configured to check both the private registry and the public npmjs.org registry (a common configuration for convenience).

The Attack:

  1. Birsan registered the name mycompany-auth on the public npmjs.org.
  2. He published version 99.0.0 (containing a harmless proof-of-concept payload — in a real attack, this would be malware).
  3. The build server runs npm install.
  4. npm's resolution logic: "I see mycompany-auth v1.0 in the private registry and v99.0 in the public registry. The public one is a higher version number."
  5. npm installs v99.0 from the public internet.
  6. The attacker's code executes inside the company's internal build environment.

The attack required no credentials, no phishing, and no zero-days. It exploited a design assumption: that higher version numbers are always better.

Mitigations

1. Scoped packages (most effective for npm/yarn):

Rename internal packages to use a company-specific scope: @mycompany/auth instead of mycompany-auth. Configure the package manager so that entire scope routes exclusively to the private registry, with no public fallback for it at all. Public registries will never have packages under a private scope if this is configured correctly, because the resolver never even asks them.

2. Namespace reservation:

Register your internal package names on the public registry as empty placeholder packages. This prevents an attacker from claiming the name. It is a defensive measure, not a primary control.

3. Private registry priority with no public fallback:

Configure your build tooling to only use the private registry, which itself proxies and vets public packages. Developers never reach npmjs.org directly.

4. Version pinning:

If you pin to [email protected] exactly (not a range), a v99.0 on the public registry will not be selected. This is defense-in-depth — pinning alone does not fully prevent confusion attacks in all package managers, but it reduces the attack surface.

Interview Tip

Dependency confusion is a favorite interview topic because it tests whether candidates understand how package managers resolve dependencies, not just how to use them. A strong answer explains the version-number resolution logic that makes the attack work, names the scoped-package mitigation for npm, and mentions that the fix is registry configuration — not application code changes.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free