Dependency confusion attacks don't require tricking a developer into mistyping anything. They exploit how package managers resolve names across multiple registries — and a correctly-typed internal package name is all that's needed.
How the attack works
Many organizations use internal package names that mirror their internal project structure — @company/auth-utils, for example — hosted on a private registry. If a package manager is configured to check both a private and public registry, and it checks the public one first (or the private package doesn't exist there at all), an attacker can publish a malicious package with the exact same name to the public registry. If your build resolves that name from the public registry instead of your intended private one, the malicious code runs in your build or application.
Why it's easy to fall into
The vulnerability isn't in your code — it's in registry resolution configuration. A build tool that isn't explicitly told "always prefer this specific private registry for this specific scope" may default to checking public registries, especially for tools with looser default resolution behavior.
Prevention
- Explicit scoping. Configure your package manager to route your organization's package scope/namespace exclusively to your private registry, with no fallback to public registries for that scope.
- Reserve the names publicly too. Publishing empty placeholder packages under your internal names on public registries (a defensive squat) prevents an attacker from claiming them, even if your resolution configuration has a gap.
- Pin exact versions with lockfiles, and verify lockfile integrity in CI — a lockfile referencing an unexpected registry source for an internal-sounding package is a red flag worth catching automatically.
- Audit registry configuration across all build environments — a fix applied to your CI pipeline but not to developer laptops still leaves a path for the attack to succeed locally.
The core lesson
This attack class exists because most build tooling assumes a single flat namespace across registries, when organizations actually operate two separate namespaces (internal and public) that happen to share syntax. Treating registry configuration as a security-relevant setting — not just a build convenience — closes the gap.