BIPI
BIPI

Dependency Confusion Attacks: How They Work and How to Prevent Them

Cybersecurity

Dependency confusion is the supply chain attack that keeps working because most package managers prefer the highest version number across all configured registries. We unpack the mechanics, walk through the famous 2021 research, and lay out the defenses that actually hold up in production.

By Arjun Raghavan, Security & Systems Lead, BIPI · August 11, 2023 · 9 min read

#dependency-confusion#supply-chain#npm#pypi#artifactory

Dependency confusion is the kind of attack that sounds too simple to work. Publish a package on the public registry with the same name as one of the targets internal packages, bump the version higher than anything they have internally, and wait for their build system to pull it in. Then run code on every developer laptop and CI runner that touched the project.

The 2021 research that landed payloads inside dozens of large companies was not a clever exploit, it was a documentation problem. Package managers resolve names across all configured registries and prefer the highest version. Most internal packages had no claim on the public namespace, so anyone could publish a higher version of them publicly.

Why it keeps working

  • npm, pip, and gem resolve across the union of configured registries
  • Internal package names leak through package.json files in public repos, error stack traces, and recruiter coding tests
  • Most teams do not register their internal package names on the public registry
  • CI runners and developer machines often have the public registry configured as a fallback

The npm specifics

npm has two real defenses, scopes and registry pinning. A scoped package like @bipi/some-utility can be pinned to a specific registry in .npmrc, and npm will never look elsewhere for that scope. Unscoped names cannot be pinned the same way. If your internal packages are unscoped, that is the first thing to fix.

The Python specifics

pip is worse here. The --index-url and --extra-index-url flags both get consulted, and pip happily picks the higher version from either. The defenses are to use --index-url alone pointing at your internal mirror, or to use a tool like pip-audit and pip-compile that pin the source registry per package. pip 22.3 added the --report flag which helps with auditing, but the resolution behavior did not change.

The Maven and NuGet specifics

Maven uses groupId, which gives you namespace isolation if you actually use a domain you own. NuGet has package source mapping which lets you bind package name patterns to specific feeds. Both languages are easier to defend than npm or pip, assuming you configure them correctly.

If your internal package names are not registered as squatting placeholders on the public registry, you are leaving the front door open.

The defenses that work

  1. Use scoped names everywhere, @org/package, never bare names
  2. Register your scope and your internal package names as placeholders on the public registry
  3. Configure CI and developer machines to use a single internal mirror, not a fallback chain
  4. Use Artifactory or Nexus virtual repositories that proxy public registries but never resolve internal names externally
  5. Add a CI check that fails the build if any dependency is pulled from an unexpected registry
  6. Pin every dependency by version and integrity hash, not just by name

The detection angle

Even with all the defenses in place, you want detection. Monitor your egress for unexpected resolution of internal package names against public registries. Most CI runners should never hit npmjs.com for internal packages. If they do, something is misconfigured.

Closing

Dependency confusion is a configuration problem with a known fix. The teams that get hit are not the ones with sophisticated threat models. They are the ones who never wrote down which registry resolves which name. Audit your resolution chain, pin every package source, and squat your own names. It is a one-week project that closes a class of attacks.

Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.