FIELD NOTE / 2026.09.224 MIN READ / 5 SOURCES

Dependency Confusion: When Public Package Names Beat Private Repositories

Dependency confusion demonstrated that build tools could fetch a public package with the same name as a private internal dependency when registry precedence and version selection were misconfigured.

The attack began with package names that leaked out of private build systems

Security researcher Alex Birsan noticed references to internal package names in public files and software artifacts. He asked a simple question: what happens if an attacker publishes a package with the same name to a public registry? In authorized research disclosed in 2021, he created benign proof-of-concept packages and found that build systems at numerous organizations downloaded them from public npm, PyPI, or RubyGems infrastructure instead of the intended private source.[1] The issue became known as dependency confusion because the resolver confused package identity across trust domains.

The vulnerability was in resolution policy rather than one vulnerable library

No special code-execution flaw was required in the package manager. The dangerous behavior came from how names, version numbers, and multiple registries were combined during dependency selection.

A higher public version could outrank an internal package

One common pattern occurred when a build configuration consulted both a private repository and a public registry. If the public package had the same unscoped name and a version that appeared newer or otherwise preferable, the resolver could select it. npm’s security guidance now explicitly describes dependency confusion as the risk of substituting a same-named public package for a private dependency and recommends scoped naming and controlled registry mapping.[2] The problem is a namespace collision with execution consequences.

Version comparison can cross a trust boundary accidentally

Semantic versioning answers which version is newer; it does not answer which publisher is authorized. Build systems need a separate rule that decides where a package name is allowed to come from.

Scopes give npm organizations a namespace that can map to a registry

npm scopes place packages under a namespace such as @company/package, and npm documents how scopes can be associated with registries.[3] That makes trust more explicit. Instead of asking every registry for an ambiguous name, the resolver can know that packages in a company’s scope must come from an approved source. Namespacing does not solve compromised credentials or malicious internal publishers, but it removes a major class of accidental public-private collision.

Names should carry provenance

A package identifier is safer when it encodes enough context to determine who controls it and where it may be resolved. Global unscoped names are convenient but easy to collide across private and public ecosystems.

Microsoft’s vcpkg documentation makes deterministic registry selection an explicit design goal

Microsoft’s vcpkg package-resolution model documents deterministic selection of a registry for a package name and notes that this design prevents dependency-confusion scenarios in which an unintended registry wins.[4] That is a useful general principle. Trust should be established before version selection. Once a package is mapped to its authoritative registry, the resolver can compare versions inside that trust domain instead of letting an unrelated public source compete.

Resolve provenance before freshness

The security order matters: first decide which registry is allowed to supply the package, then decide which acceptable version to use. Reversing those decisions can let an attacker win simply by publishing a larger version number.

OWASP recommends private scopes and explicit registry mapping

OWASP’s npm security guidance recommends using scoped package names for private dependencies and configuring registry mappings so those scopes resolve only to the intended private service.[5] It also fits into a broader defensive pattern: lock dependencies, verify integrity, limit install-script privileges, and monitor changes. Dependency confusion is one reason build configuration itself must be reviewed as security-sensitive code.

The research changed how organizations interpreted package metadata leakage

Before dependency confusion became widely known, leaking an internal package name might have looked harmless compared with leaking a password or token. The research showed that names can be security-relevant when automated tooling uses them to locate executable code. Public stack traces, package manifests, JavaScript bundles, job postings, and repository fragments can reveal internal dependency identifiers. Information classification therefore needs to consider how automation will act on disclosed metadata.

Mirrors and caches need clear trust semantics too

Many companies proxy public registries through internal artifact repositories. That can improve availability and governance, but it does not automatically prevent confusion. A proxy may still fetch a public artifact if policy says the name is unresolved internally. Safe repository managers need routing rules that distinguish internal namespaces, approved upstreams, quarantined packages, and immutable caches. The goal is to ensure that a package’s source cannot change silently because one repository happens to contain a newer version.

Why dependency confusion belongs in software-failure history

Dependency confusion belongs in software history because it revealed that package identity is not just a string. A build can be perfectly reproducible from its manifest and still be unsafe if the resolver is free to obtain the named package from the wrong trust domain. The attack turned version selection and registry configuration into security boundaries. Its enduring lesson is simple: provenance must be determined before freshness. Organizations should map private namespaces to authoritative repositories, pin and verify dependencies, and treat package resolution policy as part of the software supply chain rather than as incidental build configuration.

RESEARCH / PROVENANCE

Works Cited

5 SOURCES
  1. 01
  2. 02
  3. 03
  4. 04
  5. 05
    OWASP Cheat Sheet — NPM Security cheatsheetseries.owasp.org

CodeHistory is a living archive. Citations document the evidence used for this edition; later evidence may refine the account.

Contribute / Corrections

Improve the record.

Use this moderated submission form to suggest a correction, provide a source, challenge a priority claim or identify a missing contributor. Submissions are treated as research leads, not automatically published comments.