Skip to main content

Overview

This vulnerability, often a core component of software supply chain attacks, occurs when an application includes and executes code or functionality from an untrusted or unverified source (an “untrusted control sphere”). This includes:
  • Dependency Confusion: An attacker publishes a malicious package to a public repository (like PyPI, npm) with the same name as an internal package. The build tool might accidentally download the malicious public version instead of the trusted internal one.
  • Typosquatting: An attacker publishes a malicious package with a name very similar to a popular one (e.g., djanga instead of django).
  • Compromised Dependencies: A legitimate package is hijacked by an attacker who publishes a new, malicious version.
When the application builds or runs, it includes and executes this malicious code, leading to compromise. 📦➡️🐍

Business Impact

Including untrusted functionality is one of the most severe risks, as it effectively hands control over to the attacker:
  • Remote Code Execution (RCE): The malicious package can run any code on the build server or the production server.
  • Credential Theft: The package can steal environment variables, secrets, API keys, and developer credentials during the build or at runtime.
  • Data Exfiltration: Malicious code can read and send sensitive application data to the attacker.
  • Backdoors: The package can install persistent backdoors for future access.
  • Ransomware/Malware: The server can be compromised with ransomware or used to spread malware.

Reference Details

CWE ID: CWE-829 Related CWEs: CWE-494 (Integrity Check), CWE-1104 (Outdated Components) OWASP Top 10 (2021): A08:2021 - Software and Data Integrity Failures Severity: Critical

Framework-Specific Analysis and Remediation

This vulnerability is about the process of acquiring and managing dependencies for any framework. The defense lies in securing the build and deployment pipeline and verifying the source of all components. Key Remediation Principles:
  1. Use Private Repositories: Host internal packages on a private, authenticated repository (like a private PyPI server, npm registry, Artifactory, Nexus).
  2. Explicit Repository Configuration: Configure package managers (pip, npm, maven) to only use your trusted private repository, or to prioritize it. Ensure they don’t fall back to public repositories for internal package names.
  3. Use Lock Files: Always commit a fully resolved lock file (package-lock.json, poetry.lock, composer.lock, Gemfile.lock, yarn.lock) to version control. This ensures builds are repeatable and use the exact, vetted versions of dependencies.
  4. Use Integrity Hashes: Use requirements.txt with hashes (--hash) or npm’s package-lock.json / Yarn’s yarn.lock, which include integrity hashes (Subresource Integrity - SRI).
  5. SCA Scanning: Regularly scan dependencies for known vulnerabilities (see CWE-1104) and for suspicious packages (e.g., typosquatted names).
  6. Namespace/Scope Packages: Use private namespaces or scopes (e.g., @mycompany/internal-package in npm) to prevent name collisions with public packages.

  • Python
  • Java
  • .NET(C#)
  • PHP
  • Node.js
  • Ruby

Framework Context

Using pip with requirements.txt or pyproject.toml (Poetry/Flit) where internal package names might collide with public PyPI.

Vulnerable Scenario 1: Dependency Confusion

An internal package is named my-corp-utils. An attacker publishes a malicious package named my-corp-utils to the public PyPI.
# DANGEROUS: pip's default behavior might search public PyPI
# even if a private index is configured, and pull the malicious version
# (e.g., if it has a higher version number).
pip install -r requirements.txt
# requirements.txt (Vulnerable)
# References an internal package name that also exists publicly
my-corp-utils==1.0.2

Vulnerable Scenario 2: Typosquatting

A developer manually adds a dependency with a typo.
# DANGEROUS: Developer intended 'django' but typed 'djanga'.
# Attacker owns the 'djanga' package on PyPI.
pip install djanga
# requirements.txt (Vulnerable)
django==4.2.6
djanga==1.0.0 # Malicious package

Mitigation and Best Practices

  • Configure pip.conf to only use your internal repository, or use the --index-url and --extra-index-url flags carefully, ensuring your private index is the primary one.
  • Use pip freeze > requirements.txt to capture exact versions.
  • Use hashes in your requirements file: pip hash requirements.txt >> requirements.txt. This ensures pip install -r requirements.txt --require-hashes will fail if the package content changes.

Secure Code Example

# pip.conf (Secure - Prioritize Internal)
# [global]
# index-url = [https://private-pypi.mycorp.com/simple](https://private-pypi.mycorp.com/simple)
# extra-index-url = [https://pypi.org/simple](https://pypi.org/simple) # Use as fallback only if needed
# (Or configure to only use internal)

# requirements.txt (Secure - with Hashes)
# SECURE: Hashes ensure the downloaded package matches exactly.
# Prevents both dependency confusion and hijacked updates.
django==4.2.6 --hash=sha256:abc...123
my-corp-utils==1.0.2 \
    --hash=sha256:def...456 \
    --hash=sha256:ghi...789
Command (Secure Install):
pip install -r requirements.txt --require-hashes

Testing Strategy

Audit requirements.txt / pyproject.toml for package names. Check if any internal package names are also available for registration on public PyPI. Run SCA tools that check for typosquatting. Enforce --require-hashes or use tools like Poetry/Pipenv which use lock files with hashes by default.