Dependency Confusion
Private internal packages without a scope prefix can be hijacked by publishing a higher-versioned public package with the same name.
How It Works
npm resolves unscoped package names by checking the public registry first if you're not explicit. If your company has a private package called 'internal-utils' at version 1.0.0, an attacker publishes 'internal-utils' v9.9.9 on the public registry and npm installs the public one instead — with the attacker's code inside.
// BAD: unscoped private package name is vulnerable to confusion attacks
{
"dependencies": {
"internal-utils": "1.0.0",
"company-auth": "2.1.0"
}
}// GOOD: always scope private packages to your organization
{
"dependencies": {
"@mycompany/internal-utils": "1.0.0",
"@mycompany/company-auth": "2.1.0"
}
}Real-World Example
In 2021, security researcher Alex Birsan published a paper demonstrating dependency confusion attacks against Apple, Microsoft, PayPal, Uber, and 33 other companies. Microsoft paid him $40,000 in bug bounties for the disclosure.
How to Prevent It
- Always scope private packages with your organization name (@yourcompany/package-name)
- Configure your npm client to always resolve scoped packages from your private registry
- Add your organization scope to your .npmrc to prevent public registry fallback
- Audit package.json files for unscoped internal package names
Affected Technologies
Data Hogo detects this vulnerability automatically.
Scan Your Repo FreeRelated Vulnerabilities
Typosquatting
highInstalling a package with a name one character off from a popular library can install malware instead of the real package.
Abandoned Packages
mediumDependencies that haven't been updated in 2+ years are unlikely to receive security patches when new vulnerabilities are discovered.
Malicious Install Scripts
highnpm postinstall scripts run automatically with your system permissions during npm install, making them a common vector for malware.
Missing Lockfile
mediumWithout a lockfile, npm install resolves the latest compatible version of every dependency — which can introduce a newly compromised package on your next deploy.