Make the internal registry the default in every package manager config, set it again in CI, and block direct access to public registries at the network edge. Configuration alone is advice, not enforcement, because a developer or a script can override it with one flag.
Why config alone is not enough
Package managers read settings from several places and let closer ones win. The pip documentation lists command line options first, environment variables second and configuration files last. NuGet reads computer, user and folder level files and applies the closest. A project file can quietly change a source that an administrator set.
NuGet's own documentation is direct about this: nothing in NuGet can prevent access to sources like nuget.org, and an organization that wants to block it must use other means such as firewalls.
Four layers, in order
- Machine defaults. Push a global config to laptops and build agents. For pip that is the global pip.conf, for npm the global npmrc, for NuGet a NuGetDefaults.Config, for Maven a settings.xml with a mirror, for Go the GOPROXY variable.
- Repository config. Commit a project level file, such as .npmrc or nuget.config, so a fresh checkout behaves the same everywhere. NuGet's documentation calls a nuget.config in the solution root a good practice for repeatability.
- CI settings. Set the registry in the pipeline itself, not in the repository only, and fail the build if a lockfile contains URLs outside your registry host.
- Network rule. Allow build networks and developer machines to reach the internal registry, and deny direct access to public registries. This is the only layer that makes bypass hard.
Settings to check per tool
| Tool | Where to look | Common gap |
|---|---|---|
| npm | Project, user and global npmrc | Scoped registry lines missing for internal scopes |
| pip | pip.conf, PIP_INDEX_URL, flags | Extra index URLs that add a second source |
| Maven | settings.xml mirrorOf | Pattern misses a repository declared in a pom |
| Go | GOPROXY list | A direct entry that falls back to version control |
| NuGet | NuGet.Config hierarchy | A folder config that adds a source without clear |
Maven's guide warns about whitespace in mirrorOf lists: a value that starts with an exclusion then a space and a star mirrors nothing. Test the pattern, do not just read it.
Checking it worked
Run a clean build on a machine with an empty cache and look at the registry log. Every download should appear there. Then run the same build with the network rule temporarily bypassed in a test environment and see whether anything fails, which reveals hidden direct fetches.
Exceptions
Some tools, such as language runtimes or container pulls, use other endpoints. List them, route them through a proxy where you can, and document those you allow directly. An exception list you can read is safer than silent leaks.
Quick check
Is a lockfile check enough?
It catches resolved URLs that point elsewhere, but not a developer machine that fetched something outside the lockfile. Pair it with the network rule.
Will blocking public registries slow developers down?
Only if the proxy is slow or approval is slow. A fast pull-through cache plus automatic low risk approval keeps friction low.
Safeguard scans dependencies and builds SBOMs, runs reachability analysis, and applies policies and gates on pull requests, so the rules in this post can be checked automatically. Autonomous fix PRs are off by default, with every category on Manual. You can run a free scan at gold.safeguard.sh/scan.
Sources
- pip documentation, Configuration: precedence of command line, environment and files.
- Microsoft Learn, Common NuGet configurations: hierarchy, repeatability tip and firewall note.
- Apache Maven, Guide to Mirror Settings: mirrorOf patterns and whitespace warning.
- Go Modules Reference: GOPROXY list behavior.
Last reviewed: 19 October 2026.