Skip to content
Paul Marinos
Menu

Dependency Confusion & Supply Chain

Your code is a minority of what ships — dependency confusion and typosquatting as the entry points, lockfiles and resolver configuration as the baseline defense, and where the deeper provenance story begins.

Your own code is a minority of what ships; the rest is dependencies, and you execute code you did not write and rarely read. This is the second trusted-supply failure — the risk arrives in what you pulled in, not in a request. Dependency confusion is the sharpest single instance, but it is one entry point into a broader problem.

Dependency confusion exploits how package resolvers choose between sources. Publish a malicious public package whose name matches an organization’s internal private package, and a resolver configured to check both — preferring the higher version or the public registry — pulls the attacker’s package instead of the intended internal one. The install runs the attacker’s code in your build. It works because the resolver’s default preference was never meant to be a security decision.

The family around it shares the theme of trusting a name or a source too readily:

  • Typosquatting — a package one keystroke from a popular name (reqeusts, python-dateutil vs a lookalike), installed by a fat-fingered command or a copied-wrong tutorial.
  • Compromised maintainer — a legitimate, widely-used package whose maintainer account is taken over or whose ownership quietly changes hands, shipping a malicious update to everyone who auto-upgrades.
  • Malicious install hooks — postinstall scripts and their equivalents that run at install time, before your code ever imports the package, so review-the-import is too late.

None of these is exotic to defend against, and the baseline is cheap relative to the blast radius:

  • Pin versions and use lockfiles. A lockfile with hashes means the build resolves to the exact artifact you vetted, not “whatever is newest,” which closes both the confusion and the surprise-update paths.
  • Configure the resolver so internal names cannot be shadowed. Scoped registries, a private index that is authoritative for internal names, and explicit source pinning remove the ambiguity dependency confusion depends on. This is a configuration fix, and it fully closes the specific attack.
  • Vet before adoption, not just on CVE. A package with a single maintainer, a recent ownership change, or install-time scripts is a risk regardless of its download count. Popularity is not provenance.
  • Separate install from execution. Where possible, disable install scripts by default and build in an environment that cannot reach your secrets or production, so a malicious postinstall lands in a sandbox.

This page is the code-and-resolver layer. The heavier machinery — provenance attestation, artifact signing, SBOMs, and the SLSA levels that make “this artifact came from this reviewed source built by this builder” verifiable — is a build-system concern, covered in CI/CD and platform security. The division is deliberate: choosing and pinning dependencies is the developer’s daily decision; proving the integrity of the whole build pipeline is the platform’s.

Supply-chain risk is the trusted-supply sibling of secrets in source control in the subsection’s structure, and its provenance half is pipeline security. It has a fast-growing new surface in AI systems, where models, datasets and pickled artifacts pulled from public hubs are dependencies with the same trust problem — and, via deserialization, the same execute-on-load risk.

Graph View

Last updated:

Spotted an error on this page? Report it.