Make sure a public index can never answer for a name you own. The strongest options are to use a single index that serves both internal and public packages, or to register your internal names on the public index so nobody else can. Hash checking adds a final gate. Pick by how your builds are set up.
The risk in one paragraph
Python package indexes each have their own namespace. If a build can reach both a private index and a public one, and a name exists only privately, someone can publish that name publicly. PEP 708 describes this class of attack and cites a case where an internal package name was not claimed on PyPI and an attacker took it.
PEP 708 was rejected, so you cannot rely on a standard mechanism to settle it. See what happened to PEP 708.
Decision guide
| Your situation | Best fit | Why |
|---|---|---|
| Many teams, many private packages | One proxy index that serves public and private | One namespace you control, no second index to fall back to |
| A few internal packages, small team | Register the names on the public index | Cheap, removes the opening |
| Locked down production | Hashes plus wheel only installs | Only recorded files install |
| Offline or regulated builds | Wheelhouse with no index access | No network lookups at all |
The PEP's own guidance for pip users points the same direction: if you use a single remote repository there is nothing to do, and if you use several you should audit whether any dependency is served from more than one. For private projects with a public fallback, it suggests being explicit about where each dependency comes from, so a later registration of that name publicly cannot break or hijack your install. For project owners it suggests considering preemptively registering names in the other repositories that commonly sit alongside.
Steps
- List your internal package names. Include anything published only to a private index, even tools used by one team.
- Check each name publicly. Search the public index for the name. If it is free, decide whether to claim it. If it exists and is not yours, you have a problem: rename yours and audit where it was installed.
- Remove the second index where you can. Ask whether the public index is needed in that job at all.
- Add hashes for the production path, so a name collision cannot silently change which file installs. See pip require-hashes as the final gate.
- Name carefully. A consistent prefix makes collisions easier to spot in reviews, though a prefix is not protection by itself.
- Monitor. Alert when a public package appears with one of your internal names.
A note on placeholders
Registering a name publicly means publishing a project. Keep it clearly labelled as a placeholder, and check the public index's policies on empty or reserved projects before you do it. Do not put internal details in the description.
What not to do
Do not rely on index order. Pip does not treat extra indexes as a priority list: it considers candidates from all of them. See why extra-index-url is unsafe for private packages for why.
Make it routine
Add the name list to your repository, and a CI job that checks each name against the public index weekly. A new collision becomes a ticket, not an incident.
Safeguard's asset discovery and dependency scanning help you list which packages your projects actually use, and its policies can flag unknown names in a pull request. A free scan is available at gold.safeguard.sh/scan.
Quick check
Is a naming prefix enough protection?
No. It helps humans notice, but anyone can publish a name with your prefix on a public index.
Do I need this if I only use the public index?
No internal names are at risk then, but typos and lookalike names still are. Pin and review dependencies.
Sources
Last reviewed: 19 October 2026.