Dependency Confusion Attacks: How They Work and How to Defend Your Supply Chain
The Attack in Brief
Dependency confusion, first described publicly by Alex Birsan in 2021, exploits a behaviour common to npm, pip, gem, and several other package managers: when a package name is requested, the manager may check both the private registry and the public registry, preferring the higher version number regardless of source. An attacker who discovers a private package name — via leaked package.json files, job postings, or public source code — can publish a malicious package with the same name to the public registry with a higher version number, causing developer and CI machines to pull the attacker's package instead of the internal one.
The Scale of the Exposure
Birsan's original research demonstrated successful package substitutions at Apple, Microsoft, PayPal, Shopify, Netflix, Yelp, and Tesla, among others. Subsequent research has found that the attack vector remains viable in many enterprise environments because package manager configuration is distributed across thousands of developer machines and CI configurations, and ensuring consistent scoping across all of them is operationally difficult.
Package Manager-Specific Vectors
- npm/yarn: Private packages published without an npm scope (e.g.,
internal-utilsinstead of@company/internal-utils) are resolvable against the public registry. Scoped packages under an organisation's private scope are protected if the scope is registered on npmjs.com. - pip:
--index-urlreplaces the default PyPI index, but--extra-index-urladds PyPI as a fallback. The latter is the vulnerable configuration. - Maven: Repository precedence in
settings.xmland POM files determines resolution order. Placing the internal repository before Maven Central is necessary but not sufficient if snapshots are also resolved against Central.
Defence Controls
The primary defence is registry scoping: configuring package managers to resolve private package names exclusively from the private registry and never fall back to the public registry for those names. For npm this means using scoped package names under a registered organisation scope. For pip this means using --index-url (not --extra-index-url) for environments where all dependencies are available internally. For Maven this means configuring mirrorOf=* for the internal registry to ensure all resolution goes through it.
- Audit all CI configuration files for
--extra-index-urlor equivalent fallback-enabling flags. - Register your internal package name prefixes and scopes on public registries to prevent squatting.
- Enable package manager lockfiles and verify lockfile integrity in CI to detect unexpected resolution changes.
- Implement supply chain security tooling that alerts on unexpected package sources in dependency graphs.
OSSeva's Supply Chain Monitoring
OSSeva's Assure service includes supply chain integrity monitoring that detects dependency resolution anomalies — packages resolving from unexpected sources, version bumps without corresponding internal publish events, and new transitive dependencies introduced between builds. These signals are the earliest warning of a dependency confusion or substitution attack in progress.
Conclusion
Dependency confusion is a structural vulnerability in the package resolution model, not a bug in any single tool. Defending against it requires architectural changes to how private packages are scoped and how registries are configured, not just one-time patching. The organisations most at risk are those with large numbers of unscoped private package names and inconsistent CI configuration management.
Tags