Keyboard Navigation
W
A
S
D
or arrow keys · M for map · Q to exit
← Back to exhibits
Data IntegrityDesign FlawEXP-017

The Poisoned Dependency

When npm install ran someone else's code before yours

2010s · JavaScript / Python · 6 min read
Pattern Classification
Class
Transitive Trust
Sub-pattern
Supply Chain Inheritance
Invariant

When a system inherits trust from a source it did not verify, the attack surface extends to everything that source touches.

This Instance

Third-party code is trusted implicitly because the distribution channel is trusted

Detection Heuristic

If a system grants access, installs code, or executes actions based on the identity of a source rather than the verified content of what that source provides — trust is transitive, and the weakest link in the chain becomes the actual security boundary.

Same Pattern Class
Why It Persists

Every layer of abstraction introduces a new trust boundary. Package managers, CI/CD pipelines, container registries, AI agents — each inherits authority from the layer above without independently verifying it.

Pattern Connections
Enables
The Concatenated Query

A poisoned dependency can introduce any vulnerability — supply chain compromise is a meta-pattern that delivers other patterns

Year

2016–present

Context

Modern applications are mostly other people's code. A typical Node.js application has 300+ dependencies. A Python project pulls dozens of packages. The developer trusts npm install to download the right code, from the right author, with the right content. The package registry is the implicit trust boundary — and it has no gatekeeping. Anyone can publish a package. Anyone can name it anything. The install command runs arbitrary code during installation.

Who Built This

Package registry designers (npm, PyPI, RubyGems, Maven Central) who prioritized frictionless publishing. Application developers who added dependencies without auditing them. The entire ecosystem was designed for convenience, not trust verification.

Threat Model at Time

Malicious packages were a theoretical concern. The registries were trusted because they were popular. Nobody modeled "what if a maintainer goes rogue" or "what if someone publishes logdash next to lodash" because the developer community was assumed to be collaborative, not adversarial.

Why It Made Sense

Package registries removed the need to write common functionality. Why write an HTTP client when axios exists? Why write a date library when moment exists? The trade-off — trusting hundreds of strangers' code — was considered worth it because the alternative (writing everything yourself) was impractical.

Archaeologist's Note

This pattern has been found in applications built by talented developers at respected organizations across every decade of software history. Its presence in a codebase is not a reflection of the developer who wrote it — it is a reflection of what that developer was taught, what tools they had, and the path that was easiest given what they were taught. The goal is not to find fault. The goal is to find the pattern — before it finds you.

Katie's Law: The developers were not wrong. The shortcut was not wrong. The context changed and the shortcut didn't.

The Cloud HallThe Supply Chain Room4 / 4
Previous ExhibitMuseum Map