Python Dependency Confusion Defence
A Python build used --extra-index-url, which let pip consider packages from both internal and external repositories. I demonstrated that a higher-versioned external package with the same name as an internal dependency was selected automatically, and identified the controls to prevent dependency confusion.
Status: ASSESSED · VERIFIED
TOOLS
Objective
I set out to assess whether the Python dependency management configuration was vulnerable to dependency confusion between internal and external package repositories.
Scenario
An application relied on an internal Python package called datadbconnect, hosted on a private PyPI repository. The build configuration used --extra-index-url, which told pip to search both the internal and the public PyPI repository. I wanted to determine whether an attacker who published a higher-versioned package with the same name on the external repository could get it installed instead.
What I found
FINDING 01 (CRITICAL): BUILD CONFIGURATION SEARCHED BOTH INTERNAL AND EXTERNAL REPOSITORIES
The pip configuration used --extra-index-url, which added the external PyPI as an additional source alongside the internal repository. Pip selected the highest available version across all configured sources.
Index configuration: --extra-index-url (internal + external)
Package resolution: Highest version wins across all sources
Internal package: datadbconnect (internal version)FINDING 02 (CRITICAL): EXTERNAL PACKAGE SELECTED OVER INTERNAL
A package with the same name and a higher version number (9000.0.2) published on the external repository was selected by pip during installation. The package included a post-installation hook that executed code in the build environment.
Package installed: datadbconnect-9000.0.2 (external)
Expected package: datadbconnect (internal)
Execution context: Build container (root)The build container ran as root, so the post-installation code had full privileges inside the container.
What I did
- Identified the internal package name
The package name
datadbconnectwas discoverable through a public developer forum post. - Reviewed the pip configuration
The
--extra-index-urlsetting allowed pip to search both internal and external repositories. - Confirmed the confusion path
A package with the same name and a higher version on the external repository was selected automatically during installation.
- Assessed the impact
The external package's post-installation hook executed with root privileges inside the Docker build container.
EVIDENCE
# Dependency confusion assessment
Internal package: datadbconnect (internal PyPI)
External package: datadbconnect-9000.0.2 (external PyPI)
pip behaviour: Selected higher external version
Execution context: Docker build container as rootValidation
The external package was installed instead of the internal one, and its post-installation code executed inside the build container with root privileges. The dependency confusion path was confirmed end to end.
Before and after
| CONTROL | BEFORE | AFTER |
|---|---|---|
| Index configuration | --extra-index-url (mixed) | Risk documented; --index-url recommended |
| Package pinning | Not configured | Recommended: pin versions with hashes |
| Internal package namespace | Not reserved externally | Recommended: reserve on public PyPI |
| Build container privileges | Root | Recommended: non-root build user |
| Dependency verification | None | Recommended: hash verification + lockfile |
What I recommend
- 01Use
--index-url(not--extra-index-url) to point pip at a single trusted source, or use a repository manager that proxies and prioritises internal packages. - 02Pin all dependencies to exact versions with hash verification in a lockfile.
- 03Reserve internal package names on public PyPI to prevent name squatting.
- 04Run build containers as a non-root user to limit the impact of malicious post-installation hooks.
- 05Scan dependencies for unexpected version changes or new packages matching internal names.
“Dependency managers must be configured to trust the correct package source and verify dependencies because an attacker can publish a higher-version package with the same name and turn the build process into a code-execution path.”
SKILLS IT PROVES
- Software Supply Chain Security
- Dependency Management
- DevSecOps
- CI/CD Security
- Vulnerability Assessment
- Secure Configuration Management
- Python Security
- Container Security
- Package Management
- Access Control
- Supply Chain Risk Management