← Concepts & Glossary
Signing & Supply Chain Trust

Dependency Confusion

An attack that exploits name collisions between internal and public package registries.

What is dependency confusion?

Dependency confusion is a supply chain attack in which an adversary publishes a malicious package to a public registry (npm, PyPI, RubyGems) under the same name as a private, internal-only package used by a target organisation. When the target's package manager resolves dependencies, it may prefer the attacker's public copy — usually because it carries a higher version number — and silently execute attacker code during installation.

The technique was formalised in 2021 by security researcher Alex Birsan, who used it to obtain remote code execution inside Apple, Microsoft, PayPal, Uber, Shopify, Netflix, and more than thirty other major firms — and earned over $130,000 in bug bounties in a single research campaign.

How it works

The attack exploits three assumptions that package managers historically made:

  1. Discovery. The attacker finds the names of an organisation's internal packages — leaked in a public package.json, an error stack trace, a screenshot in a blog post, or a stale GitHub commit.
  2. Public publication. The attacker registers a package with the same name on the relevant public registry — usually with a very high version number like 9999.9.9 — and embeds a postinstall script or import-time payload that phones home with environment variables, SSH keys, or CI secrets.
  3. Resolution. When the target's CI or developer machine runs npm install or pip install, the package manager consults both the internal mirror and the public registry. Without explicit priority rules, the highest semver wins — and the malicious package is pulled, installed, and executed.

Why it matters — and how to mitigate

Dependency confusion is devastating because the attack surface is every internal package name a company has ever used, and the blast radius is arbitrary code execution on the developer or CI machine — which usually means cloud credentials, secrets, and source-repository tokens.

The mitigations are straightforward but require discipline: (1) scope locks — publish internal npm packages under an @my-org/ scope and claim that scope publicly; (2) private registry priority — configure package managers so the internal registry resolves first and public is a fallback, never an override; (3) explicit version pins and lockfiles that record the resolved URL, not just the version; (4) ingress filtering at the proxy layer to block resolution of names that match internal ones.

What detection value a platform adds

  • Inventory every internal package name

    You cannot defend names you do not know about — platforms surface every package referenced across repos, CI, and production images.

  • Detect unclaimed public namespaces

    Flag internal package names whose matching public namespace is still available — those are live bait for attackers.

  • Continuously monitor new public publications

    If a package matching one of your internal names suddenly appears on npm or PyPI, you want to know within minutes, not weeks.

  • Enforce lockfile-URL integrity

    Policy gates can reject any build where a lockfile resolves an internal-name package to a public URL.

  • Shift proxy configuration into audit

    A platform can verify that every developer machine and CI runner is configured with the correct private-registry priority — and alert on drift.

How Safeguard uses it

Safeguard maintains a live inventory of every internal package name observed across your SBOMs, and cross-references that list against public-registry publications in near-real-time. If an unclaimed name appears publicly, the platform raises a high-severity supply chain finding and drafts the namespace-claim remediation.

See if your internal names are exposed.

Safeguard inventories every internal package you ship and checks the public namespaces on your behalf.