Context: This document forms the theoretical foundation of the NPM Supply Chain Network Analysis project. It explains why the topological risk model used in the project is necessary, through the lens of active threats in the ecosystem.
Node Package Manager (NPM) is the world's largest software registry, hosting over 3 million packages and processing billions of downloads weekly. Modern software development processes heavily rely on third-party code libraries (dependencies) to increase speed. However, when a single NPM package is added to a project, an average of 79 transitive (indirect) packages are also implicitly included in the trust chain.
This "implicit trust" model makes NPM an attractive target for attackers. By compromising a single popular package or a dependency deep within it, attackers gain access to a "one-to-many" distribution mechanism that can affect millions of developers and end users. This document defines the active threats in the NPM ecosystem and the technical defense mechanisms that should be taken against them.
The following attack vectors represent the most common and critical techniques targeting the modern software supply chain.
Risk Level: High
Definition: When an attacker or careless developer copies a legitimate package and
publishes it under a new name without referencing the original package.
package.json file
of the copied package but retains all or part of the code.package-lock.json or
npm-shrinkwrap.json files are manipulated to "pin" older versions with known
security vulnerabilities in the dependency tree.
npm audit don't know the relationship between the clone and the original package,
they cannot detect this vulnerability. This causes known vulnerabilities to persist in the
system through "ghost" versions.
Risk Level: Medium-High
Definition: Publishing malicious packages with names similar to popular packages (e.g.,
raect instead of react or clolors instead of colors).
npm install command.
preinstall or postinstall scripts in package.json, attempting to
steal environment variables or SSH keys from the system.
Risk Level: Critical
Definition: Publishing the same name as a private package used by companies in their
internal networks on the public NPM registry with a higher version number.
@internal/auth-utils (v1.0.0)@internal/auth-utils (v99.0.0)Risk Level: Critical
Definition: Compromise of trusted package developer accounts (due to weak passwords,
phishing, or leaked tokens) and injection of malicious code into their packages.
.npmrc
file in the compromised system, infecting hundreds of packages.Risk Level: High
Definition: A legitimate package owner intentionally breaking (sabotaging) the package or
adding malicious functionality to it.
node-ipc or faker.js incidents,
the developer adds code that deletes files at specific IP addresses or locks the system by entering an
infinite loop for political or personal reasons to their popular package.minor or
patch updates (expected to be safe according to SemVer rules) and target automatic update
mechanisms (e.g., ^1.0.0).
The defense-in-depth principle should be applied to narrow the attack surface.
| Method | Description and Implementation |
|---|---|
npm ci Usage |
Never use npm install in CI/CD environments. npm ci (clean install)
adheres to versions in package-lock.json, doesn't update package.json,
and guarantees reproducibility of installation. |
| Lockfile Analysis | Lockfiles contain integrity hashes (SHA-512) and resolved URLs of
packages. Tools like lockfile-lint should be used to check whether packages are
being downloaded from untrusted sources (e.g., attacker's own server). |
| Script Disabling | If possible, use the npm install --ignore-scripts parameter during installation to
prevent the execution of preinstall and postinstall scripts, which are
most commonly used by attackers. |
For internal company packages, Scoped Packages in the format
@company/package-name must be used. This informs the NPM registry that the package belongs to a
user or organization and allows the .npmrc file to route this scope only to the private
registry (e.g., Artifactory, Verdaccio) to prevent Dependency Confusion attacks.
Two-Factor Authentication (2FA) should be made mandatory for NPM accounts (especially for
accounts with publish privileges). When using Automation Tokens, granular authorizations should
be set to allow only necessary packages and IP addresses (CIDR whitelist).
install
script.Developers should pay particular attention to the following areas in the package.json file:
scripts: Are there curl, wget, or encrypted
(base64) commands in the preinstall, postinstall areas?dependencies: Are there typos in names (Typosquatting)? Do version numbers
make sense?| Attack Type | Primary Vector | Key Mitigation |
|---|---|---|
| Shrinkwrapped Clones | Cloned/Modified Code | Source code analysis, OSSF Scorecard (Maintenance metrics) |
| Typosquatting | Name Similarity | Careful package name verification, Scoped packages usage |
| Dependency Confusion | Version Priority | @scope usage, Private registry configuration (.npmrc) |
| Account Takeover | Identity Theft | Mandatory 2FA, Granular Tokens |
| Malicious Updates | Automatic Updates (^, ~) |
Dependency Pinning (Version Pinning), npm ci |
| Install Scripts | postinstall Scripts |
--ignore-scripts, Socket.dev behavior analysis |