Scope - What This Guide Covers
This guide addresses dependency confusion and typo-squatting attacks targeting Python package installations. You'll find concrete verification steps, tooling recommendations, and a framework for securing your package management workflow. While focused on PyPI, the principles extend to npm, RubyGems, and other public repositories.
This is a practitioner's reference for the specific problem of malicious packages masquerading as legitimate dependencies.
Key Concepts and Definitions
Typo-squatting: An attacker registers a package name with a slight variation from a popular package (e.g., jeilyfish vs. jellyfish). A typo during installation or in a requirements file can pull the malicious version.
Dependency confusion: An attacker uploads a package to a public repository with the same name as your organization's private package. Package managers may pull the public (malicious) version if not configured correctly.
Package verification: Confirming a package's authenticity before installation, including name validation, maintainer verification, and signature checking where available.
Requirements Breakdown
Your compliance framework may not mention "typo-squatting" explicitly, but these requirements apply:
PCI DSS v4.0.1 Requirement 6.3.2: Addresses securing custom software and preventing unauthorized code. Malicious packages in your dependency tree constitute unauthorized code in your application.
OWASP Top 10 A06:2021 - Vulnerable and Outdated Components: Encompasses supply chain risks including malicious dependencies.
ISO/IEC 27001:2022 Control 8.31: Your dependency management process must ensure only verified packages enter each environment.
NIST 800-53 Rev 5 SA-12: Requires mechanisms to protect against supply chain threats. Package verification is a technical control supporting this requirement.
Implementation Guidance
Pre-Installation Verification
Before adding any new dependency:
Check the exact package name against official documentation. Don't trust autocomplete or memory.
Review the package metadata on PyPI directly:
- Publication date
- Maintainer information
- Download statistics
- Homepage and repository links
Examine the package source before first use:
pip download --no-deps package-name tar -xzf package-name-*.tar.gz # Review setup.py and core modules
Lock File Discipline
Your requirements.txt or Pipfile.lock must specify exact versions with hashes:
jellyfish==0.9.0 \
--hash=sha256:4d93d1b6a4f...
This prevents typo-squatting and version substitution attacks. Regenerate lock files in a controlled environment.
Automated Scanning Integration
Tools like Snyk scan your dependencies against known malicious package databases:
- They detect known threats.
- Configure your scanner to alert on new dependencies.
- Set up alerts for packages with similar names to your dependencies.
Private Package Index Configuration
For organizations with internal packages, configure pip to prefer your private index:
# pip.conf or pip.ini
[global]
index-url = https://your-private-pypi.internal/simple/
extra-index-url = https://pypi.org/simple/
This reduces dependency confusion risk but doesn't eliminate typo-squatting. You still need name verification.
Developer Workstation Controls
Your developers' machines are the entry point for malicious packages:
- Disable automatic dependency installation in IDEs. Require explicit review.
- Use virtual environments for all projects.
- Monitor SSH and GPG key access. Configure file integrity monitoring on
~/.ssh/and~/.gnupg/.
Common Pitfalls
Trusting package download counts: Attackers can inflate these.
Assuming PyPI reviews packages: PyPI is a public registry with minimal pre-publication review.
Installing packages without reviewing changes: Even legitimate packages can be compromised.
Relying solely on automated tools: Manual verification for new dependencies is essential.
Skipping verification in CI/CD: Your CI/CD should verify package hashes, not just install whatever the lock file specifies.
Quick Reference Table
| Verification Step | Tool/Method | Frequency | Catches |
|---|---|---|---|
| Package name confirmation | Manual review against official docs | Every new dependency | Typo-squatting |
| Metadata review | PyPI web interface | Every new dependency | Suspicious patterns |
| Source code inspection | pip download + manual review |
New dependencies, major updates | Malicious code |
| Hash verification | pip with --require-hashes |
Every installation | Package substitution |
| Dependency scanning | Snyk, safety, pip-audit | Daily in CI/CD | Known malicious packages |
| Lock file regeneration | Controlled environment only | Dependency updates only | Compromised developer machines |
| Similarity monitoring | Custom script or service | Weekly | New typo-squat attempts |
| Credential monitoring | File integrity monitoring | Continuous | Exfiltration attempts |
Your dependency management process should treat every package as untrusted until verified. The jeilyfish package proved that malicious code can persist in public repositories for extended periods. Your verification steps are the only reliable defense.



